Introducción
Este es un Notebook de R Markdown. Cuando se ejecuta código dentro del notebook, los resultados aparecen debajo del código.
Pueden ingresar a Canvas aquí.
El código se puede ejecutar de varias maneras:
- Haciendo clic en el botón de Run,
- Haciendo clic en el botón de Play en cada “chunk” (o pedazo de código),
- Tecleando Ctrl+Shift+Enter dentro del “chunk” deseado.
Se pueden agregar nuevos “chunks” tecleando Ctrl+Alt+I o dando clic en Insert Chunk.
[1] 21
[1] 348
Cuando se escribe código en R no es necesario dejar espacios entre los comandos, pero sí es recomendable:
noeslomismoqueyoescribaasí a que yo escriba así.
R se puede utilizar como una calculadora. Las operaciones básicas se representan de la siguiente manera:
| Suma |
+ |
| Resta |
- |
| Multiplicación |
* |
| División |
/ |
| Potencia |
^ ó ** |
Cuando simplemente realizamos alguna operación, esta se va a ejecutar en la consola, pero no se va a almacenar ningún resultado. Para poder almacenar datos, tablas, etc. es necesario definir variables. La convención en R para hacerlo es escribiendo una “flecha”: <- o -> (la más utilizada es la primera <-).
# esto es un comentario dentro del chunk de código
3 + 4
[1] 7
[1] 12
x <- 3 + 5 + 8 + 7 + 13 + 21 +
14 +
4
x
[1] 75
[1] 81
[1] 81
Para ver la versión renderizada del código, hay que hacer clic en el botón Preview.
NOTA: Aquí no es necesario escribir un “#” al inicio de la línea para crear texto (y no código).
Cuando se trabaja en RStudio, podemos crear proyectos (Rproj) que nos permiten organizar nuestro análisis de datos, junto con las tablas originales, los resultados, etc., de tal manera que es muy fácil de compartir y replicar por otras personas o en otros equipos.
Para dar claridad al código, se pueden agregar encabezados de distintos niveles. Esto se logra agregando un “#” Al inicio (para el primer orden de encabezado), “##” para el segundo, “###” para el tercero, etc.
Gráficas con ggplot2
Primero cargaremos los datos que utilizaremos de ejemplo para graficar.
Después de analizar cada variable, vemos que las vars. categóricas (factores) están marcadas como “chr” (character o texto), por lo cual sería conveniente cambiar algunas de ellas a factores.
Podemos agregar nuevas filas a una tabla utilizando la función add_row(). Aquí se deben especificar los valores para cada una de las variables (columnas), de lo contrario, R lo tomará como un valor omitido NA.
mpg %>% # pipe operator "luego"
add_row(manufacturer = "jeep",
displ = 2,
year = 2008,
cyl = 4,
trans = "manual(m6)",
cty = 15,
hwy = 24,
fl = "p",
class = "suv"
)
Si queremos cambiar el fabricante a factor y hwy (que está medida en “millas por galón” a “km por litro”), podemos usar mutate():
mpg %>%
mutate(
cty = cty * 1.609 / 3.785,
hwy = hwy * 1.609 / 3.785,
manufacturer = as_factor(manufacturer),
model = as_factor(model),
)
Si queremos aplicar la misma transformación a varias vars. podemos usar mutate_at() para escoger las variables, o mutate_if() para que, con base en una condición, R escoja las variables a modificar:
mpg %>%
pull(manufacturer) %>%
is.character()
[1] TRUE
is.character(pull(mpg, manufacturer))
[1] TRUE
mpg %>%
mutate_at(
.vars = c("manufacturer", "model", "drv"),
.funs = as_factor
)
mpg_editada <- mpg %>%
mutate_if(
.predicate = is.character,
.funs = as_factor
)
mpg_editada
mpg_editada %>%
pull(manufacturer) %>%
is.character()
[1] FALSE
mpg_editada %>%
group_by(trans) %>%
summarise(media = mean(cty),
n = n()) %>%
arrange(n)
[1] 0.1495726
mpg_editada2 <- mpg %>%
mutate_if(
.predicate = is.character,
.funs = as_factor
) %>%
mutate(trans = fct_lump_min(trans, 20,
other_level = "Otros"))
mpg_editada2
mpg_editada2 %>%
group_by(trans) %>%
summarise(media = mean(cty),
n = n()) %>%
arrange(n)
Teniendo nuestros datos ya limpios, podemos proceder a graficarlos y conocer varios tipos de gráficas que se pueden hacer con ggplot2.
Graficaremos la var. displ en el eje x y la variable hwy en el eje y. Haremos un diagrama de dispersión.

mpg_editada2 %>%
ggplot() +
geom_point(mapping = aes(x = displ, y = hwy))

mpg_editada2 %>%
ggplot(mapping = aes(x = displ, y = hwy)) +
geom_point()

mpg_editada2 %>%
ggplot(mapping = aes(x = displ, y = hwy)) +
geom_line()

Un gráfico de ggplot siempre comenzará con la función ggplot(), que genera un sistema de coordenadas, al que agregamos capas. En este caso, agregamos una capa de “puntos”, mapeando, a traves de aes() las variables x ^ y.
Disclaimer: Los gráficos anteriores son de carácter meramente ilustrativo. Como se aprecia en los warnings, algunas de esas configuraciones no son ideales para este tipo de variables.
Otras personalizaciones
Si, por otro lado, se quisiera cambiar alguno de esos atributos por default, sin que éstos dependan de alguna variable, se puede hacer si se especifican fuera del aes()
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ,
y = hwy),
color = "blue")

Cuidado, porque si se pone dentro del aes() no va a dar el resultado que buscamos:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = "indianred1")) +
ggtitle("Definir el color fijo dentro del aes() produce errores")

ggplot(mpg) +
geom_point(mapping = aes(x = displ, y = hwy),
color = "blue",
fill = "orange",
shape = 22,
size = 2,
alpha = 0.2
)

También se pueden juntar varios de estos atributos al mismo tiempo, si eso se deseara:
ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ,
y = hwy,
color = class,
shape = drv,
size = cyl),
alpha = 0.7)

Se pueden asociar varias características a la misma variable:
ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ,
y = hwy,
color = class,
shape = class,
size = class),
alpha = 0.7)

Varias gráficas en una sola con patchwork
Los gráficos que recién creamos pueden ser almacenados en variables. La paquetería patchwork nos permite juntar dos o más gráficas de ggplot en una sola imagen. Retomemos algunas de las gráficas anteriores.
NOTA: El nombre se escoge arbitrariamente.
# Las gráficas a poner en una sola imagen
g1 <- ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ, y = hwy)) +
ggtitle("La gráfica más básica")
g2 <- ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ, y = hwy, color = class))+
ggtitle("Color variable")
g3 <- ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ, y = hwy), color = "blue")+
ggtitle("Color fijo")
g4 <- ggplot(data = mpg_editada2) +
geom_point(mapping = aes(x = displ,
y = hwy,
color = class,
shape = drv,
size = cyl),
alpha = 0.7) +
ggtitle("Col, forma y tam var, alpha fija")
El acomodo se puede guardar en una variable también. Con patchwork es bastante intuitiva la manera de acomodar las gráficas.
+ sirve para agregar gráficos en esa línea (también funciona utilizar |).




/ sirve para crear una nueva fila.
fig1 <- g1 /
(g2 + g3) /
g4
fig1

Se pueden agregar títulos y subtítulos globales con plot_annotation(). También, se puede dejar espacios en blanco usando plot_spacer():
fig1 +
plot_annotation(title = "Gráficas con ggplot2",
subtitle = "Cambiando la estética de varias maneras")

(g1 + plot_spacer()) /
(g4) /
(g2 + g3) +
plot_annotation(title = "Gráficas con ggplot2",
subtitle = "Otro acomodo distinto")

mpg_editada2 %>%
ggplot(aes(x = manufacturer, y = displ)) +
geom_boxplot()

Uso de facetas
Otra opción para personalizar gráficas es utilizar facetas. Esto divide nuestro gráfico en varios subgráficos, de acuerdo a alguna variable especificada.
facet_wrap()
Para separar los subgráficos con base en una variable:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ,
y = hwy,
color = class,
shape = drv),
alpha = 0.7) +
ggtitle("Facetas por cilindraje") +
facet_wrap(~ cyl)

facet_grid()
Las facetas se pueden poner en ambos ejes, usando dos variables:
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ,
y = hwy,
color = class),
alpha = 0.5) +
ggtitle("Facetas por tracción y cilindraje") +
facet_grid(cyl ~ drv)

Gráficas de líneas
Otro tipo de gráfico muy utilizado es el de líneas. Usaremos otro conjunto de datos para esto.
Se puede acceder a la documentación de este dataset (y de cualquier función), a través de la función help():
Estos datos que hemos trabajado son de tipo tibble. Podemos observar lgunas diferencias entre un objeto tibble y un data.frame tradicional:
Tibble
Te muestra solo las primeras 10 filas, así como el tipo de datos de cada columna. También te da en resumen la dimensión de la tabla (filas x columnas).
economics
# A tibble: 574 x 6
# date pce pop psavert uempmed unemploy
# <date> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 1967-07-01 507. 198712 12.6 4.5 2944
# 2 1967-08-01 510. 198911 12.6 4.7 2945
# 3 1967-09-01 516. 199113 11.9 4.6 2958
# 4 1967-10-01 512. 199311 12.9 4.9 3143
# 5 1967-11-01 517. 199498 12.8 4.7 3066
# 6 1967-12-01 525. 199657 11.8 4.8 3018
# 7 1968-01-01 531. 199808 11.7 5.1 2878
# 8 1968-02-01 534. 199920 12.3 4.5 3001
# 9 1968-03-01 544. 200056 11.7 4.1 2877
# 10 1968-04-01 544 200208 12.3 4.6 2709
# ... with 564 more rows
Data.frame
as.data.frame(economics)
# date pce pop psavert uempmed unemploy
# 1 1967-07-01 506.7 198712 12.6 4.5 2944
# 2 1967-08-01 509.8 198911 12.6 4.7 2945
# 3 1967-09-01 515.6 199113 11.9 4.6 2958
# 4 1967-10-01 512.2 199311 12.9 4.9 3143
# 5 1967-11-01 517.4 199498 12.8 4.7 3066
# 6 1967-12-01 525.1 199657 11.8 4.8 3018
# 7 1968-01-01 530.9 199808 11.7 5.1 2878
# 8 1968-02-01 533.6 199920 12.3 4.5 3001
# 9 1968-03-01 544.3 200056 11.7 4.1 2877
# 10 1968-04-01 544.0 200208 12.3 4.6 2709
# 11 1968-05-01 549.8 200361 12.0 4.4 2740
# 12 1968-06-01 556.3 200536 11.7 4.4 2938
# 13 1968-07-01 563.2 200706 10.7 4.5 2883
# 14 1968-08-01 567.0 200898 10.5 4.2 2768
# 15 1968-09-01 568.2 201095 10.6 4.6 2686
# 16 1968-10-01 571.6 201290 10.8 4.8 2689
# 17 1968-11-01 576.7 201466 10.6 4.4 2715
# 18 1968-12-01 576.5 201621 11.1 4.4 2685
# 19 1969-01-01 583.5 201760 10.3 4.4 2718
# 20 1969-02-01 588.7 201881 9.7 4.9 2692
# 21 1969-03-01 588.9 202023 10.2 4.0 2712
# 22 1969-04-01 593.9 202161 9.7 4.0 2758
# 23 1969-05-01 600.3 202331 10.1 4.2 2713
# 24 1969-06-01 600.9 202507 11.1 4.4 2816
# 25 1969-07-01 602.7 202677 11.8 4.4 2868
# 26 1969-08-01 609.9 202877 11.5 4.4 2856
# 27 1969-09-01 613.2 203090 11.6 4.7 3040
# 28 1969-10-01 618.5 203302 11.4 4.5 3049
# 29 1969-11-01 620.5 203500 11.6 4.8 2856
# 30 1969-12-01 622.8 203675 11.8 4.6 2884
# 31 1970-01-01 628.7 203849 11.8 4.6 3201
# 32 1970-02-01 634.0 204008 11.7 4.5 3453
# 33 1970-03-01 632.3 204156 12.4 4.6 3635
# 34 1970-04-01 636.0 204401 13.3 4.1 3797
# 35 1970-05-01 642.4 204607 12.4 4.7 3919
# 36 1970-06-01 646.3 204830 12.3 4.9 4071
# 37 1970-07-01 648.5 205052 13.5 5.1 4175
# 38 1970-08-01 652.9 205295 13.4 5.4 4256
# 39 1970-09-01 659.1 205540 12.9 5.2 4456
# 40 1970-10-01 658.3 205788 13.1 5.2 4591
# 41 1970-11-01 656.6 206024 13.6 5.6 4898
# 42 1970-12-01 665.6 206238 13.2 5.9 5076
# 43 1971-01-01 676.1 206466 13.3 6.2 4986
# 44 1971-02-01 679.4 206668 13.3 6.3 4903
# 45 1971-03-01 682.0 206855 13.5 6.4 4987
# 46 1971-04-01 688.8 207065 13.2 6.5 4959
# 47 1971-05-01 691.1 207260 13.6 6.7 4996
# 48 1971-06-01 699.8 207462 14.7 5.7 4949
# 49 1971-07-01 698.9 207661 13.8 6.2 5035
# 50 1971-08-01 704.9 207881 13.6 6.4 5134
# 51 1971-09-01 713.0 208114 13.3 5.8 5042
# 52 1971-10-01 715.8 208345 13.3 6.5 4954
# 53 1971-11-01 720.9 208555 13.1 6.4 5161
# 54 1971-12-01 728.4 208740 13.0 6.2 5154
# 55 1972-01-01 731.5 208917 12.5 6.2 5019
# 56 1972-02-01 736.2 209061 12.8 6.6 4928
# 57 1972-03-01 749.2 209212 11.8 6.6 5038
# 58 1972-04-01 752.5 209386 11.5 6.7 4959
# 59 1972-05-01 758.0 209545 11.7 6.6 4922
# 60 1972-06-01 761.6 209725 11.7 5.4 4923
# 61 1972-07-01 769.9 209896 11.7 6.1 4913
# 62 1972-08-01 776.3 210075 12.0 6.0 4939
# 63 1972-09-01 781.1 210278 12.2 5.6 4849
# 64 1972-10-01 794.9 210479 13.0 5.7 4875
# 65 1972-11-01 800.5 210656 13.6 5.7 4602
# 66 1972-12-01 806.1 210821 13.7 6.1 4543
# 67 1973-01-01 816.5 210985 12.4 5.7 4326
# 68 1973-02-01 825.8 211120 12.5 5.2 4452
# 69 1973-03-01 832.8 211254 12.7 5.5 4394
# 70 1973-04-01 835.7 211420 13.2 5.0 4459
# 71 1973-05-01 841.6 211577 13.2 4.9 4329
# 72 1973-06-01 844.3 211746 13.6 5.0 4363
# 73 1973-07-01 854.1 211909 13.2 5.2 4305
# 74 1973-08-01 853.3 212092 13.9 4.9 4305
# 75 1973-09-01 869.2 212289 13.1 5.4 4350
# 76 1973-10-01 868.2 212475 14.4 5.5 4144
# 77 1973-11-01 876.9 212634 14.4 5.1 4396
# 78 1973-12-01 876.6 212785 14.8 4.7 4489
# 79 1974-01-01 884.5 212932 14.3 5.0 4644
# 80 1974-02-01 889.7 213074 14.2 5.1 4731
# 81 1974-03-01 901.4 213211 13.4 4.8 4634
# 82 1974-04-01 910.8 213361 13.1 5.0 4618
# 83 1974-05-01 922.4 213513 12.8 4.6 4705
# 84 1974-06-01 928.0 213686 12.8 5.3 4927
# 85 1974-07-01 937.9 213854 12.8 5.7 5063
# 86 1974-08-01 954.8 214042 12.1 5.0 5022
# 87 1974-09-01 955.1 214246 12.9 5.3 5437
# 88 1974-10-01 959.2 214451 13.4 5.5 5523
# 89 1974-11-01 956.2 214625 13.8 5.2 6140
# 90 1974-12-01 961.8 214782 14.0 5.7 6636
# 91 1975-01-01 975.6 214931 13.2 6.3 7501
# 92 1975-02-01 989.4 215065 12.5 7.1 7520
# 93 1975-03-01 990.6 215198 12.7 7.2 7978
# 94 1975-04-01 995.0 215353 14.2 8.7 8210
# 95 1975-05-01 1018.9 215523 17.3 9.4 8433
# 96 1975-06-01 1026.8 215768 14.3 8.8 8220
# 97 1975-07-01 1039.8 215973 12.6 8.6 8127
# 98 1975-08-01 1047.0 216195 13.0 9.2 7928
# 99 1975-09-01 1054.8 216393 13.0 9.2 7923
# 100 1975-10-01 1060.9 216587 13.4 8.6 7897
# 101 1975-11-01 1075.8 216771 12.7 9.5 7794
# 102 1975-12-01 1092.1 216931 12.0 9.0 7744
# 103 1976-01-01 1107.1 217095 11.7 9.0 7534
# 104 1976-02-01 1107.7 217249 12.3 8.2 7326
# 105 1976-03-01 1114.9 217381 12.2 8.7 7230
# 106 1976-04-01 1125.4 217528 11.7 8.2 7330
# 107 1976-05-01 1122.7 217685 12.3 8.3 7053
# 108 1976-06-01 1140.5 217861 11.4 7.8 7322
# 109 1976-07-01 1149.6 218035 11.7 7.7 7490
# 110 1976-08-01 1158.0 218233 11.7 7.9 7518
# 111 1976-09-01 1168.8 218440 11.4 7.8 7380
# 112 1976-10-01 1176.8 218644 11.1 7.7 7430
# 113 1976-11-01 1189.0 218834 11.4 8.4 7620
# 114 1976-12-01 1211.5 219006 10.6 8.0 7545
# 115 1977-01-01 1215.0 219179 10.6 7.5 7280
# 116 1977-02-01 1231.3 219344 9.3 7.2 7443
# 117 1977-03-01 1238.3 219504 10.5 7.2 7307
# 118 1977-04-01 1247.3 219684 10.5 7.3 7059
# 119 1977-05-01 1257.1 219859 10.3 7.9 6911
# 120 1977-06-01 1263.6 220046 10.6 6.2 7134
# 121 1977-07-01 1280.5 220239 10.5 7.1 6829
# 122 1977-08-01 1285.7 220458 10.9 7.0 6925
# 123 1977-09-01 1294.5 220688 11.1 6.7 6751
# 124 1977-10-01 1311.4 220904 11.0 6.9 6763
# 125 1977-11-01 1327.0 221109 11.2 7.0 6815
# 126 1977-12-01 1336.0 221303 11.4 6.8 6386
# 127 1978-01-01 1329.5 221477 11.9 6.5 6489
# 128 1978-02-01 1355.1 221629 11.1 6.7 6318
# 129 1978-03-01 1377.5 221792 11.0 6.2 6337
# 130 1978-04-01 1396.4 221991 10.8 6.1 6180
# 131 1978-05-01 1412.0 222176 10.3 5.7 6127
# 132 1978-06-01 1425.8 222379 10.0 6.0 6028
# 133 1978-07-01 1426.8 222585 10.9 5.8 6309
# 134 1978-08-01 1447.0 222805 10.5 5.8 6080
# 135 1978-09-01 1452.9 223053 10.6 5.6 6125
# 136 1978-10-01 1466.9 223271 10.7 5.9 5947
# 137 1978-11-01 1480.6 223477 10.5 5.5 6077
# 138 1978-12-01 1496.5 223670 10.4 5.6 6228
# 139 1979-01-01 1502.4 223865 11.1 5.9 6109
# 140 1979-02-01 1517.8 224053 11.1 5.9 6173
# 141 1979-03-01 1531.2 224235 11.2 5.9 6109
# 142 1979-04-01 1538.4 224438 11.0 5.4 6069
# 143 1979-05-01 1558.8 224632 10.3 5.6 5840
# 144 1979-06-01 1575.7 224843 9.9 5.6 5959
# 145 1979-07-01 1586.1 225055 10.6 5.9 5996
# 146 1979-08-01 1615.6 225295 9.7 4.8 6320
# 147 1979-09-01 1633.9 225547 9.4 5.5 6190
# 148 1979-10-01 1641.6 225801 9.7 5.5 6296
# 149 1979-11-01 1657.3 226027 9.7 5.3 6238
# 150 1979-12-01 1666.3 226243 10.1 5.7 6325
# 151 1980-01-01 1697.3 226451 9.9 5.3 6683
# 152 1980-02-01 1701.4 226656 10.1 5.8 6702
# 153 1980-03-01 1708.2 226849 10.2 6.0 6729
# 154 1980-04-01 1695.2 227061 11.3 5.8 7358
# 155 1980-05-01 1700.1 227251 11.4 5.7 7984
# 156 1980-06-01 1718.8 227522 11.2 6.4 8098
# 157 1980-07-01 1747.1 227726 11.3 7.0 8363
# 158 1980-08-01 1763.8 227953 11.3 7.5 8281
# 159 1980-09-01 1780.5 228186 11.7 7.7 8021
# 160 1980-10-01 1817.1 228417 11.3 7.5 8088
# 161 1980-11-01 1826.8 228612 11.6 7.7 8023
# 162 1980-12-01 1851.7 228779 11.4 7.5 7718
# 163 1981-01-01 1870.0 228937 10.9 7.4 8071
# 164 1981-02-01 1884.2 229071 10.8 7.1 8051
# 165 1981-03-01 1902.9 229224 10.8 7.1 7982
# 166 1981-04-01 1904.4 229403 10.9 7.4 7869
# [ reached 'max' / getOption("max.print") -- omitted 408 rows ]
Grafiquemos el desempleo a lo largo del tiempo.
ggplot(economics,
aes(x = date, y = unemploy)) +
geom_line()

Filtrando los datos y añadiendo dos capas de gráficos (puntos y líneas):
ggplot(economics %>% filter(year(date)>=2006),
aes(x = date, y = unemploy)) +
geom_line(color = "red") +
geom_point(size = 1, color ="forestgreen")

Sería exactamente el mismo resultado si definimos el aes() dentro de cada uno de los geoms:
ggplot(economics %>% filter(year(date)>=2006)) +
geom_line(aes(x = date, y = unemploy), color = "red") +
geom_point(aes(x = date, y = unemploy), size = 1, color ="forestgreen")

Se pueden crear sus propias tibbles directamente en R con la función tibble():
Transformación de datos con dplyr
Utilizaremos los datos de gapminder para revisar varios ejemplos. Explorando la tabla, vemos que contiene 1,704 filas con 6 columnas:
- País
country
- Continente
continent
- Año
year
- Esperanza de vida (en años)
lifeExp
- Población
pop
- PIB per cápita (en USD, ajustados por la inflación)
gdpPercap
data(gapminder)
gapminder
gapminder %>%
distinct(country) %>%
nrow()
[1] 142
# levels(gapminder$country)
Si quisiéramos filtrar la tabla para mantener sólo los países asiáticos, lo podríamos lograr con el verbo filter(). Opcionalmente, podríamos validar con distinct() si nuestro filtro logró el objetivo:
# Para quedarnos solo con países asiáticos
gapminder %>%
filter(continent == "Asia")
# Validación
gapminder %>%
filter(continent == "Asia") %>%
distinct(continent)
gapminder %>%
distinct(continent)
Vemos que las filas de la tabla se redujeron (a 396) y que, efectivamente, logramos el objetivo de mantener puros países de Asia.
Podemos ordenar una tabla con respecto a una de sus variables con arrange(). Por defáult, el orden será ascendente. Si se desea en orden descendente, agregamos desc(). Probemos mostrando a los países que tienen la mayor población en el año 2007.
gapminder %>%
filter(year == 2007) %>%
arrange(desc(pop))
Para quedarnos con los años a partir de 1997.
gapminder %>%
filter(year >= 1997)
Pero si quisiéramos quedarnos con los años 1952, 1972, 2002, 2007, ¿cómo lo podríamos hacer?
Esto no funcionaría como esperamos:
Esto marca error, porque después de cada coma es otra condición distinta que R evalúa.
gapminder %>%
filter(year == 1952,1972,2002,2007)
Error: Problem with `filter()` input `..2`.
x Input `..2` must be a logical vector, not a double.
i Input `..2` is `1972`.
Esto no da error, pero no es el resultado que buscamos.
gapminder %>%
filter(year == c(1952,1972,2002,2007))
Lo podríamos lograr con la función %in%:
gapminder %>%
filter(year %in% c(1952, 1972, 2002, 2007),
country == "Mexico")
Ahora, si deseáramos obtener una subgráfica de líneas de cuatro países asiáticos (Nepal, Irak, Cambodia y China), lo podríamos hacer de la siguiente forma:
\(y = 3x + 4\)
y ~ 3x + 4
gapminder %>%
filter(country %in% c("Nepal", "Iraq", "Cambodia","China")) %>%
ggplot(aes(x = year, y = lifeExp)) +
geom_line() +
facet_wrap(vars(country)) +
ggtitle("Separación de los países por facetas")

Otra alternativa sería mostrar una sola gráfica y definir el color de línea por país. Aquí se ejemplifica también cómo cambiar el nombre de los ejes, la posición de la leyenda, entre otros.
gapminder %>%
filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>%
ggplot(aes(x = year, y = lifeExp, color = country)) +
geom_line() +
ylab("Esperanza de vida (años)") + xlab("") +
ggtitle("Cambio de la esperanza de vida para algunos paises asiáticos") +
labs(color = "") +
theme(legend.position = "top")

Otra manera de especificar los nombres de ejes y el título es directamente dentro de labs():
izq <- theme(legend.position = "left")
gapminder %>%
filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>%
ggplot(aes(x = year, y = lifeExp, color = country)) +
geom_line() +
labs(x = "",
y = "Esperanza de vida (años)",
title = "Cambio de la esperanza de vida en algunos países asiáticos",
color = "") +
theme_classic(base_size = 18,
base_family = "serif",
base_line_size = 1) +
theme(legend.position = "top")

Se podrían hacer más configuraciones:
gapminder %>%
filter(country %in% c("Indonesia","India","Oman", "Taiwan")) %>%
ggplot(aes(x = year, y = lifeExp, color = country, linetype = country)) +
geom_line() +
ylab("Esperanza de vida (años)") +
xlab("") +
ggtitle("Cambio de la esperanza de vida para algunos paises asiáticos") +
labs(color = "", linetype ="") +
theme(legend.position = "bottom")

Podemos analizar la relación entre la esperanza de vida y el PIB per cápita, ya que se dice que existe una relación directa entre ambas.
Haremos el análisis para el año 2007:
gapminder %>%
filter(year == 2007) %>%
ggplot(aes(x = gdpPercap, y = lifeExp, color = continent,
size = pop)) +
geom_point() +
scale_x_log10() +
ylab("Esperanza de vida (años)") +
xlab("PIB per cápita (USD con ajuste inflacionario, escala log10)") +
labs(color ="", size="")

gapminder %>%
filter(country %in% c("Canada", "Mexico", "Brazil"),
year == 2007) %>%
select(year, country, pop)
Si quisiéramos graficar la población total por continente, esto estaría mal:
gapminder %>%
ggplot(aes(x = year, y = pop, color = continent)) +
geom_line()

Cambiarla a una gráfica de puntos (dispersión) nos empieza a dar más claridad de por qué estaba mal: tenemos un punto por cada país.
gapminder %>%
ggplot(aes(x = year, y = pop, color = continent)) +
geom_point()

Podríamos vernos tentados a querer filtrar la tabla por continente y año, para luego juntar todo y graficarlo. Algo como:
gapminder %>%
filter(continent == "Africa",
year == 1952) %>%
summarise(poblacion_total = sum(pop))
Pero, rápido nos damos cuenta que esto sería bastante largo y tedioso.
¿Cómo podríamos graficar la población total por continente, a lo largo del tiempo? Tendríamos que agregar la población de cada país de cada continente y graficar eso.
tabla <- gapminder %>%
group_by(continent, year) %>%
summarise(poblacion = sum(pop), .groups = "drop_last")
tabla
tabla %>%
summarise(pob_promedio = mean(poblacion))
`summarise()` ungrouping output (override with `.groups` argument)
tabla %>%
ggplot(aes(x = year, y = poblacion, color = continent)) +
geom_line()

¿Cómo podríamos agregar la población total del mundo a esta gráfica? (Nota: la escala no nos permitirá ver bien a cada continente).
#poblacion mundial total
pob_total <- gapminder %>%
group_by(year) %>%
summarise(poblacion = sum(pop), .groups = "drop_last")
g_pob <- gapminder %>%
group_by(continent, year) %>%
summarise(poblacion = sum(pop), .groups = "drop_last") %>%
ggplot(aes(x = year)) +
geom_line(aes(y = poblacion, color = continent)) +
# para incluir la pob. mundial total:
geom_line(data = pob_total, aes(x = year, y = poblacion),
color = "firebrick", linetype = "dashed")
g_pob


Pero, ¿qué pasa si queremos observar el cambio de estos factores a lo largo del tiempo? Claro, podríamos crear muchas gráficas distintas, cambiando el argumento filter(year == "cada uno de los años"). Pero esto, aparte de que sería laborioso, no sería práctico para analizarlo.
Gráficas interactivas
plotly
Lo que podemos hacer es crear una gráfica interactiva, apoyados de la paquetería plotly. Los cambios que tenemos que hacer en este caso en particular son muy sencillos. Pueden consultar este libro electrónico para más detalles.
- Haber instalado y cargado
plotly
- Agregar
aes(frame = year) a la estética de la gráfica.
- Guardar el gráfico en una variable (el nombre es indiferente), y posteriormente ejecutar la función
ggplotly() con la variable que contiene al gráfico.
NOTA: Casi cualquier gráfico hecho con ggplot2 se puede convertir en uno interactivo con la función ggplotly().
Convirtamos la gráfica anterior a interactiva, simplemente corriendo la función ggplotly()
gapminder %>%
filter(continent == "Oceania",
year == 2007)
int_plot1 <- gapminder %>%
ggplot(aes(x = gdpPercap, y = lifeExp, color = continent,
size = pop, label = country)) +
geom_point(aes(frame = year)) +
scale_x_log10() +
ylab("Esperanza de vida (años)") +
xlab("PIB per cápita (USD con ajuste inflacionario)") +
labs(color ="", size="")
Ignoring unknown aesthetics: frame
prueba <- gapminder %>%
filter(year == 2007) %>%
ggplot(aes(x = gdpPercap, y = lifeExp, color = country,
size = pop, label = country)) +
geom_point(aes(frame = continent)) +
scale_x_log10() +
ylab("Esperanza de vida (años)") +
xlab("PIB per cápita (USD con ajuste inflacionario)") +
labs(color ="", size="")
Ignoring unknown aesthetics: frame
number of items to replace is not a multiple of replacement lengthnumber of items to replace is not a multiple of replacement length
int_plot2 <- gapminder %>%
ggplot(aes(x = gdpPercap, y = lifeExp, color = country,
size = pop, label = country)) +
geom_point(aes(frame = year)) +
scale_x_log10() +
facet_wrap(~ continent) +
ylab("Esperanza de vida (años)") +
xlab("PIB per cápita (USD con ajuste inflacionario)") +
# labs(color ="", size="")
theme(legend.position = "none")
Ignoring unknown aesthetics: frame
`group_by_()` is deprecated as of dplyr 0.7.0.
Please use `group_by()` instead.
See vignette('programming') for more help
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
Otro tipo de gráfico que puede proporcionarnos mucha información es un diagrama de caja y bigotes. Aquí, la interpretación es algo así:
- Los bigotes muestran los valores mínimo y máximo (sin considerar outliers),
- el inicio de la caja representa el primer cuartil (25% de los datos),
- La línea interna de la caja es la mediana (el 50% de los datos),
- el final de la caja muestra el tercer cuartil (75% de los datos) y,
- en caso de que la gráfica muestre puntos fuera de la caja, se considerarían como outliers.
gapminder %>%
filter(year == 2007) %>%
summarise(esperanza_vida = mean(lifeExp))
gapminder %>%
filter(year == 2007) %>%
group_by(continent) %>%
summarise(esperanza_vida = mean(lifeExp))
`summarise()` ungrouping output (override with `.groups` argument)
gap_box <- gapminder %>%
filter(year == 2007) %>%
ggplot(aes(x = continent, y = lifeExp)) +
geom_boxplot()
ggplotly(gap_box)
Definiendo una función especial, se pueden crear gráficas acumulativas de líneas también:
invisible(getSymbols("AAPL",src='yahoo'))
㤼㸱getSymbols㤼㸲 currently uses auto.assign=TRUE by default, but will
use auto.assign=FALSE in 0.5-0. You will still be able to use
㤼㸱loadSymbols㤼㸲 to automatically load data. getOption("getSymbols.env")
and getOption("getSymbols.auto.assign") will still be checked for
alternate defaults.
This message is shown once per session and may be disabled by setting
options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
AAPL download failed; trying again.
df <- data.frame(Date=zoo::index(AAPL),coredata(AAPL))
df <- tail(df, 30)
df$ID <- seq.int(nrow(df))
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
df <- df %>%
accumulate_by(~ID)
p <- ggplot(df,aes(ID, AAPL.Close, frame = frame)) +
geom_line()
fig <- ggplotly(p) %>%
layout(
title = "AAPL: Last 30 days",
yaxis = list(
title = "Close",
zeroline = F,
tickprefix = "$"
),
xaxis = list(
title = "Day",
zeroline = F,
showgrid = F
)
) %>%
animation_opts(
frame = 100,
transition = 0,
redraw = FALSE
) %>%
animation_slider(
currentvalue = list(
prefix = "Day "
)
)
fig
Warning in for (i in seq_len(n)) { :
closing unused connection 3 (https://query2.finance.yahoo.com/v7/finance/download/AAPL?period1=1167609600&period2=1598486400&interval=1d&events=history&crumb=qg6NVAeFT8v)
Gráfico2 <- gapminder %>%
group_by(continent, year) %>%
summarise(poblacion = sum(pop), .groups = "drop_last") %>%
ggplot(aes(x = year, y = poblacion, color = continent)) +
geom_point(aes(frame = year)) +
ylab("Población") +
xlab("Año") +
labs(color ="", size="")
Ignoring unknown aesthetics: frame
Error in gregexpr(calltext, singleline, fixed = TRUE) :
regular expression is invalid UTF-8
gganimate
Esto no funciona igual para un gráfico de líneas. Existe otra paquetería que nos permite hacer cosas similares: gganimate. Esta página contiene un breve tutorial de varias opciones.
NOTA: *Se requiere instalar las paqueterías png y gifski adicionales a gganimate.
p1 <- gapminder %>%
filter(country %in% c("Mexico", "United States", "Chile")) %>%
ggplot(aes(x = year, y = lifeExp,
color = country)) +
geom_line() +
theme(legend.position = "top") +
labs(x = "Año", y = "Esperanza de vida (años)",
title = "Evolución de la esperanza de vida en el tiempo")
p1 + transition_reveal(year)
anim_save(filename = "figs/LifeExp_gganim.gif")

p <- ggplot(
airquality,
aes(Day, Temp, group = Month, color = factor(Month))
) +
geom_line() +
scale_color_viridis_d() +
labs(x = "Day of Month", y = "Temperature") +
theme(legend.position = "top")
p + transition_reveal(Day)
anim_save(filename = "figs/airquality.gif")
LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYSBSIg0Kc3VidGl0bGU6ICJBcHJlbmRpZW5kbyBhIHVzYXIgUiINCmF1dGhvcjogIlBhYmxvIEJlbmF2aWRlcyBIZXJyZXJhIg0KZGF0ZTogMjAyMC0wNS0yNw0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KIyBJbnRyb2R1Y2Npw7NuDQoNCkVzdGUgZXMgdW4gTm90ZWJvb2sgZGUgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pLiBDdWFuZG8gc2UgZWplY3V0YSBjw7NkaWdvIGRlbnRybyBkZWwgbm90ZWJvb2ssIGxvcyByZXN1bHRhZG9zIGFwYXJlY2VuIGRlYmFqbyBkZWwgY8OzZGlnby4gDQoNClB1ZWRlbiBpbmdyZXNhciBhICoqQ2FudmFzKiogW2FxdcOtXShodHRwczovL2l0ZXNvLmluc3RydWN0dXJlLmNvbSkuDQoNCkVsIGPDs2RpZ28gc2UgcHVlZGUgZWplY3V0YXIgZGUgdmFyaWFzIG1hbmVyYXM6DQoNCiogSGFjaWVuZG8gY2xpYyBlbiBlbCBib3TDs24gZGUgKlJ1biosDQoqIEhhY2llbmRvIGNsaWMgZW4gZWwgYm90w7NuIGRlICpQbGF5KiBlbiBjYWRhICJjaHVuayIgKG8gcGVkYXpvIGRlIGPDs2RpZ28pLA0KKiBUZWNsZWFuZG8gKkN0cmwrU2hpZnQrRW50ZXIqIGRlbnRybyBkZWwgImNodW5rIiBkZXNlYWRvLiANCg0KU2UgcHVlZGVuIGFncmVnYXIgbnVldm9zICJjaHVua3MiIHRlY2xlYW5kbyAqQ3RybCtBbHQrSSogbyBkYW5kbyBjbGljIGVuICpJbnNlcnQgQ2h1bmsqLg0KDQpgYGB7cn0NCjMgKiA3DQoxMiAqIDI5DQpgYGANCg0KKioqDQoNCkN1YW5kbyBzZSBlc2NyaWJlIGPDs2RpZ28gZW4gKipSKiogbm8gZXMgbmVjZXNhcmlvIGRlamFyIGVzcGFjaW9zIGVudHJlIGxvcyBjb21hbmRvcywgcGVybyBzw60gZXMgcmVjb21lbmRhYmxlOg0KDQo+IG5vZXNsb21pc21vcXVleW9lc2NyaWJhYXPDrSBhIHF1ZSB5byBlc2NyaWJhIGFzw60uDQoNCioqUioqIHNlIHB1ZWRlIHV0aWxpemFyIGNvbW8gdW5hIGNhbGN1bGFkb3JhLiBMYXMgb3BlcmFjaW9uZXMgYsOhc2ljYXMgc2UgcmVwcmVzZW50YW4gZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KfE9wZXJhY2nDs24gICAgICB8IFPDrW1ib2xvIHwNCnw6LS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS06fA0KfCAgICBTdW1hICAgICAgIHwgICAgKyAgICB8DQp8ICAgIFJlc3RhICAgICAgfCAgICAtICAgIHwNCnxNdWx0aXBsaWNhY2nDs24gfCAgICAqICAgIHwNCnwgIERpdmlzacOzbiAgICAgfCAgICAvICAgIHwNCnwgUG90ZW5jaWEgICAgICB8ICBeIMOzICoqIHwNCg0KQ3VhbmRvIHNpbXBsZW1lbnRlIHJlYWxpemFtb3MgYWxndW5hIG9wZXJhY2nDs24sIGVzdGEgc2UgdmEgYSBlamVjdXRhciBlbiBsYSBjb25zb2xhLCBwZXJvIG5vIHNlIHZhIGEgYWxtYWNlbmFyIG5pbmfDum4gcmVzdWx0YWRvLiBQYXJhIHBvZGVyIGFsbWFjZW5hciBkYXRvcywgdGFibGFzLCBldGMuIGVzIG5lY2VzYXJpbyBkZWZpbmlyICoqdmFyaWFibGVzKiouIExhIGNvbnZlbmNpw7NuIGVuICoqUioqIHBhcmEgaGFjZXJsbyBlcyBlc2NyaWJpZW5kbyB1bmEgKiJmbGVjaGEiKjogYDwtYCBvIGAtPmAgKGxhIG3DoXMgdXRpbGl6YWRhIGVzIGxhIHByaW1lcmEgYDwtYCkuDQoNCg0KDQpgYGB7ciBwcnVlYmF9DQojIGVzdG8gZXMgdW4gY29tZW50YXJpbyBkZW50cm8gZGVsIGNodW5rIGRlIGPDs2RpZ28NCjMgKyA0DQo0ICogMw0KeCA8LSAzICsgNSArIDggKyA3ICsgMTMgKyAyMSArDQogIDE0ICsgDQogIDQNCngNCg0KMyAqKiA0DQozIF4gNA0KYGBgDQoNClBhcmEgdmVyIGxhIHZlcnNpw7NuIHJlbmRlcml6YWRhIGRlbCBjw7NkaWdvLCBoYXkgcXVlIGhhY2VyIGNsaWMgZW4gZWwgYm90w7NuICpQcmV2aWV3Ki4NCg0KKipOT1RBOioqICpBcXXDrSBubyBlcyBuZWNlc2FyaW8gZXNjcmliaXIgdW4gIiMiIGFsIGluaWNpbyBkZSBsYSBsw61uZWEgcGFyYSBjcmVhciB0ZXh0byAoeSBubyBjw7NkaWdvKS4qDQoNCkN1YW5kbyBzZSB0cmFiYWphIGVuIFJTdHVkaW8sIHBvZGVtb3MgY3JlYXIgcHJveWVjdG9zIChScHJvaikgcXVlIG5vcyBwZXJtaXRlbiBvcmdhbml6YXIgbnVlc3RybyBhbsOhbGlzaXMgZGUgZGF0b3MsIGp1bnRvIGNvbiBsYXMgdGFibGFzIG9yaWdpbmFsZXMsIGxvcyByZXN1bHRhZG9zLCBldGMuLCBkZSB0YWwgbWFuZXJhIHF1ZSBlcyBtdXkgZsOhY2lsIGRlIGNvbXBhcnRpciB5IHJlcGxpY2FyIHBvciBvdHJhcw0KcGVyc29uYXMgbyBlbiBvdHJvcyBlcXVpcG9zLg0KDQoNClBhcmEgZGFyIGNsYXJpZGFkIGFsIGPDs2RpZ28sIHNlIHB1ZWRlbiBhZ3JlZ2FyIGVuY2FiZXphZG9zIGRlIGRpc3RpbnRvcyBuaXZlbGVzLiBFc3RvIHNlIGxvZ3JhIGFncmVnYW5kbyB1biAiIyIgQWwgaW5pY2lvIChwYXJhIGVsIHByaW1lciBvcmRlbiBkZSBlbmNhYmV6YWRvKSwgIiMjIiBwYXJhIGVsIHNlZ3VuZG8sICIjIyMiIHBhcmEgZWwgdGVyY2VybywgZXRjLg0KDQojIEVuY2FiZXphZG8gdGlwbyAxDQpIb2xhDQoNCiMjIEVuY2FiZXphZG8gdGlwbyAyDQoNCkhvbGEgMg0KDQojIyMgRW5jYWJlemFkbyB0aXBvIDMNCg0KSG9sYSAzDQoNCk90cmEgdmVudGFqYSBkZSBpbmNsdWlyIHNlY2Npb25lcyBlbiBzdSBjw7NkaWdvIGVzIHF1ZSBlc28gdGUgcGVybWl0ZSBuYXZlZ2FyIGRlIG1hbmVyYSByw6FwaWRhIGVudHJlIGVsbGFzLg0KDQpPdHJvIGF0YWpvIGRlbCB0ZWNsYWRvIHF1ZSBlcyBtdXkgw7p0aWwgZXMgKCpDVFJMICsgRW50ZXIqKSwgcXVlIHNpcnZlIHBhcmEgY29ycmVyIGxhKHMpIGzDrW5lYShzKSBkZSBjw7NkaWdvIHNlbGVjY2lvbmFkYShzKSwgbyAoKkNUUkwgKyBTaGlmdCArIEVudGVyKikgcGFyYQ0KY29ycmVyIHRvZG8gZWwgImNodW5rIi4gUC4gZWouOg0KDQpgYGB7ciBoZWxsby13b3JsZH0NCnByaW50KCLCoUhvbGEsIG11bmRvISIpDQpwcmludCgiwqFBZGnDs3MsIG11bmRvISIpDQpgYGANCg0KUHVlZGVuIGFncmVnYXIgZWN1YWNpb25lcyBkZSAkXExhVGVYJDoNCg0KJCQNClxzdW1fe2k9MX1ebnszeF9pICsgNH0NCiQkDQpUYW1iacOpbiBwdWVkZW4gZXNjcmliaXIgZWN1YWNpb25lcyBkZW50cm8gZGUgdW5hIGzDrW5lYSBkZSB0ZXh0byBjb24gJFxzdW1fe2k9MX1ebnszeF9pICsgNH0kIHNvbG8gdW4gc2lnbm8gZGUgcGVzb3MgKCQpLg0KDQoqKlB1ZWRlbiBlbmNvbnRyYXIgdW5hIGd1w61hIG11eSBjb21wbGV0YSBzb2JyZSBSIE1hcmtkb3duIFthcXXDrV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykuKioNCg0KIyMgQ2FyZ2EgZGUgcGFxdWV0ZXLDrWFzDQoNClVuYSBidWVuYSBwcsOhY3RpY2EgZXMgY2FyZ2FyIHRvZGFzIGxhcyBwYXF1ZXRlcsOtYXMgbmVjZXNhcmlhcyAgYWwgaW5pY2lvIGRlbCBjw7NkaWdvLCBqdW50byBjb24gdmFyaWFibGVzIHF1ZSBzZSBlc3BlY2lmaXF1ZW4gbWFudWFsbWVudGUuIEVzdG8gcGVybWl0ZSBzZXIgbcOhcyBjbGFyb3Mgc29icmUgcHJlcnJlcXVpc2l0b3MgbyBjb25zaWRlcmFjaW9uZXMgcXVlIHNlIHJlYWxpemFuLiBTaSBsYSBwYXF1ZXRlcsOtYSBubyBlc3TDoSBpbnN0YWxhZGEsIGVzIG5lY2VzYXJpbyBpbnN0YWxhcmxhIGNvbiBgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIilgLCBwLiBlai4NCg0KYGBge30NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpgYGANCg0KDQoNCmBgYHtyIHBrZ3MsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShwYXRjaHdvcmspDQpsaWJyYXJ5KGdhcG1pbmRlcikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShnZ2FuaW1hdGUpDQpsaWJyYXJ5KHF1YW50bW9kKQ0KYGBgDQoNCiMgR3LDoWZpY2FzIGNvbiBgZ2dwbG90MmANCg0KUHJpbWVybyBjYXJnYXJlbW9zIGxvcyBkYXRvcyBxdWUgdXRpbGl6YXJlbW9zIGRlIGVqZW1wbG8gcGFyYSBncmFmaWNhci4NCg0KYGBge3IgZGF0b3MxfQ0KZGF0YShtcGcpDQptcGcNCmBgYA0KDQpEZXNwdcOpcyBkZSBhbmFsaXphciBjYWRhIHZhcmlhYmxlLCB2ZW1vcyBxdWUgbGFzIHZhcnMuIGNhdGVnw7NyaWNhcyAoZmFjdG9yZXMpIGVzdMOhbiBtYXJjYWRhcyBjb21vICJjaHIiIChjaGFyYWN0ZXIgbyB0ZXh0byksIHBvciBsbyBjdWFsIHNlcsOtYSBjb252ZW5pZW50ZSBjYW1iaWFyIGFsZ3VuYXMgZGUgZWxsYXMgYSBmYWN0b3Jlcy4NCg0KUG9kZW1vcyBhZ3JlZ2FyIG51ZXZhcyBmaWxhcyBhIHVuYSB0YWJsYSB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBhZGRfcm93KClgLiBBcXXDrSBzZSBkZWJlbiBlc3BlY2lmaWNhciBsb3MgdmFsb3JlcyBwYXJhIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMgKCpjb2x1bW5hcyopLCBkZSBsbyBjb250cmFyaW8sIGBSYCBsbyB0b21hcsOhIGNvbW8gdW4gdmFsb3Igb21pdGlkbyBgTkFgLg0KDQpgYGB7ciBkYXRvczEtbXV0YXRlfQ0KbXBnICU+JSAjIHBpcGUgb3BlcmF0b3IgImx1ZWdvIg0KICBhZGRfcm93KG1hbnVmYWN0dXJlciA9ICJqZWVwIiwNCiAgICAgICAgICBkaXNwbCAgICAgICAgPSAyLA0KICAgICAgICAgIHllYXIgICAgICAgICA9IDIwMDgsDQogICAgICAgICAgY3lsICAgICAgICAgID0gNCwNCiAgICAgICAgICB0cmFucyAgICAgICAgPSAibWFudWFsKG02KSIsDQogICAgICAgICAgY3R5ICAgICAgICAgID0gMTUsDQogICAgICAgICAgaHd5ICAgICAgICAgID0gMjQsDQogICAgICAgICAgZmwgICAgICAgICAgID0gInAiLA0KICAgICAgICAgIGNsYXNzICAgICAgICA9ICJzdXYiDQogICAgICAgICAgKSANCmBgYA0KU2kgcXVlcmVtb3MgY2FtYmlhciBlbCBmYWJyaWNhbnRlIGEgZmFjdG9yIHkgaHd5IChxdWUgZXN0w6EgbWVkaWRhIGVuICJtaWxsYXMgcG9yIGdhbMOzbiIgYSAia20gcG9yIGxpdHJvIiksIHBvZGVtb3MgdXNhciBgbXV0YXRlKClgOg0KDQoNCmBgYHtyfQ0KbXBnICU+JSANCiAgbXV0YXRlKA0KICAgIGN0eSA9IGN0eSAqIDEuNjA5IC8gMy43ODUsDQogICAgaHd5ID0gaHd5ICogMS42MDkgLyAzLjc4NSwNCiAgICBtYW51ZmFjdHVyZXIgPSBhc19mYWN0b3IobWFudWZhY3R1cmVyKSwNCiAgICBtb2RlbCA9IGFzX2ZhY3Rvcihtb2RlbCksDQogICAgDQogICkNCmBgYA0KDQoNCg0KU2kgcXVlcmVtb3MgYXBsaWNhciBsYSBtaXNtYSB0cmFuc2Zvcm1hY2nDs24gYSB2YXJpYXMgdmFycy4gcG9kZW1vcyB1c2FyIGBtdXRhdGVfYXQoKWAgcGFyYSBlc2NvZ2VyIGxhcyB2YXJpYWJsZXMsIG8gYG11dGF0ZV9pZigpYCBwYXJhIHF1ZSwgY29uIGJhc2UgZW4gdW5hIGNvbmRpY2nDs24sIFIgZXNjb2phIGxhcyB2YXJpYWJsZXMgYSBtb2RpZmljYXI6DQoNCmBgYHtyfQ0KbXBnICU+JSANCiAgcHVsbChtYW51ZmFjdHVyZXIpICU+JSANCiAgaXMuY2hhcmFjdGVyKCkNCg0KaXMuY2hhcmFjdGVyKHB1bGwobXBnLCBtYW51ZmFjdHVyZXIpKQ0KYGBgDQoNCg0KYGBge3J9DQptcGcgJT4lIA0KICBtdXRhdGVfYXQoDQogICAgLnZhcnMgPSBjKCJtYW51ZmFjdHVyZXIiLCAibW9kZWwiLCAiZHJ2IiksDQogICAgLmZ1bnMgPSBhc19mYWN0b3INCiAgKQ0KDQptcGdfZWRpdGFkYSA8LSAgbXBnICU+JSANCiAgbXV0YXRlX2lmKA0KICAgIC5wcmVkaWNhdGUgPSBpcy5jaGFyYWN0ZXIsDQogICAgLmZ1bnMgICAgICA9IGFzX2ZhY3RvciANCiAgKQ0KDQptcGdfZWRpdGFkYQ0KDQptcGdfZWRpdGFkYSAlPiUgDQogIHB1bGwobWFudWZhY3R1cmVyKSAlPiUgDQogIGlzLmNoYXJhY3RlcigpDQpgYGANCg0KYGBge3J9DQptcGdfZWRpdGFkYSAlPiUgDQogIGdyb3VwX2J5KHRyYW5zKSAlPiUgDQogIHN1bW1hcmlzZShtZWRpYSA9IG1lYW4oY3R5KSwNCiAgICAgICAgICAgIG4gICAgID0gbigpKSAlPiUgDQogIGFycmFuZ2UobikNCg0KMzUvMjM0DQpgYGANCg0KYGBge3IgZGF0b3MxLW11dGF0ZTJ9DQptcGdfZWRpdGFkYTIgPC0gbXBnICU+JSANCiAgbXV0YXRlX2lmKA0KICAgIC5wcmVkaWNhdGUgPSBpcy5jaGFyYWN0ZXIsDQogICAgLmZ1bnMgICAgICA9IGFzX2ZhY3RvciANCiAgKSAlPiUgDQogIG11dGF0ZSh0cmFucyA9IGZjdF9sdW1wX21pbih0cmFucywgMjAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3RoZXJfbGV2ZWwgPSAiT3Ryb3MiKSkNCm1wZ19lZGl0YWRhMg0KDQptcGdfZWRpdGFkYTIgJT4lIA0KICBncm91cF9ieSh0cmFucykgJT4lIA0KICBzdW1tYXJpc2UobWVkaWEgPSBtZWFuKGN0eSksDQogICAgICAgICAgICBuICAgICA9IG4oKSkgJT4lIA0KICBhcnJhbmdlKG4pDQpgYGANCg0KVGVuaWVuZG8gbnVlc3Ryb3MgZGF0b3MgeWEgbGltcGlvcywgcG9kZW1vcyBwcm9jZWRlciBhIGdyYWZpY2FybG9zIHkgY29ub2NlciB2YXJpb3MgdGlwb3MgZGUgZ3LDoWZpY2FzIHF1ZSBzZSBwdWVkZW4gaGFjZXIgY29uIGBnZ3Bsb3QyLmANCg0KR3JhZmljYXJlbW9zIGxhIHZhci4gZGlzcGwgZW4gZWwgZWplIHggeSBsYSB2YXJpYWJsZSBod3kgZW4gZWwgZWplIHkuIEhhcmVtb3MgdW4gZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24uDQoNCmBgYHtyIGdlb21fcG9pbnR9DQpwbG90KGNhcnMpDQoNCm1wZ19lZGl0YWRhMiAlPiUgDQogIGdncGxvdCgpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQ0KDQptcGdfZWRpdGFkYTIgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIA0KICBnZW9tX3BvaW50KCkNCg0KbXBnX2VkaXRhZGEyICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKw0KICBnZW9tX2xpbmUoKQ0KYGBgDQoNCg0KVW4gZ3LDoWZpY28gZGUgZ2dwbG90IHNpZW1wcmUgY29tZW56YXLDoSBjb24gbGEgZnVuY2nDs24gYGdncGxvdCgpYCwgcXVlIGdlbmVyYSB1biBzaXN0ZW1hIGRlIGNvb3JkZW5hZGFzLCBhbCBxdWUgYWdyZWdhbW9zIGNhcGFzLiBFbiBlc3RlIGNhc28sIGFncmVnYW1vcyB1bmEgY2FwYSBkZSAicHVudG9zIiwgbWFwZWFuZG8sIGEgdHJhdmVzIGRlIGBhZXMoKWAgbGFzIHZhcmlhYmxlcyAqeCogXiAqeSouDQoNCg0KIyMgTW9kaWZpY2FyIGVsIGNvbG9yLCBmb3JtYSB5IHRhbWHDsW8gey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQpTaSBzZSBkZXNlYSBjb250cm9sYXIgZWwgY29sb3IsIGZvcm1hLCB0YW1hw7FvLCB0cmFuc3BhcmVuY2lhLCBldGMuIGEgdHJhdsOpcyBkZSBhbGd1bmEgb3RyYSB2YXJpYWJsZSwgc2UgcHVlZGUgaGFjZXIgaW5jbHV5w6luZG9sYSBkZW50cm8gZGVsIGBhZXMoKWAgZGVsIGBnZ3Bsb3QoKWAuDQoNCiMjIyBDb2xvcg0KDQpBaG9yYSBxdWVyZW1vcyBjYW1iaWFyIGVsIGBjb2xvcmAgZGUgbG9zIHB1bnRvcywgZGUgYWN1ZXJkbyBhIHVuYSB0ZXJjZXJhIHZhcmlhYmxlOiBsYSBjbGFzZSBkZSBhdXRvIChgY2xhc3NgKS4NCg0KYGBge3IgZ2VvbV9wb2ludC1jb2xvcn0NCm1wZ19lZGl0YWRhMiAlPiUgDQpnZ3Bsb3QoKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MpDQogICAgICAgICAgICAgKQ0KYGBgDQoNCiMjIyBGb3JtYQ0KDQpEZSBmb3JtYSBhbHRlcm5hdGl2YSwgcHVkaW1vcyBoYWJlciBjYW1iaWFkbyBsYSBmb3JtYSBkZSBsb3MgcHVudG9zLCBkZXBlbmRpZW5kbyBsYSBjbGFzZSAoZW4gdmV6IGRlbCBjb2xvciksIGNvbiBgc2hhcGVgLg0KDQpgYGB7ciBnZW9tX3BvaW50LXNoYXBlfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IGNsYXNzKSkNCmBgYA0KDQojIyMgVHJhbnNwYXJlbmNpYQ0KTyBsYSB0cmFuc3BhcmVuY2lhIGRlIGxvcyBtaXNtb3MgY29uIGBhbHBoYWA6DQoNCmBgYHtyIGdlb21fcG9pbnQtYWxwaGF9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gY2xhc3MpKQ0KYGBgDQoNCiMjIyBUYW1hw7FvDQoNCk8gZWwgdGFtYcOxbyBjb24gYHNpemVgOg0KDQpgYGB7ciBnZW9tX3BvaW50LXNpemV9DQpnZ3Bsb3QoZGF0YSA9IG1wZykgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBjbGFzcykpDQpgYGANCg0KIyMgey19DQoqKkRpc2NsYWltZXI6KiogKkxvcyBncsOhZmljb3MgYW50ZXJpb3JlcyBzb24gZGUgY2Fyw6FjdGVyIG1lcmFtZW50ZSBpbHVzdHJhdGl2by4gQ29tbyBzZSBhcHJlY2lhIGVuIGxvcyB3YXJuaW5ncywgYWxndW5hcyBkZSBlc2FzIGNvbmZpZ3VyYWNpb25lcyBubyBzb24gaWRlYWxlcyBwYXJhIGVzdGUgdGlwbyBkZSB2YXJpYWJsZXMuKg0KDQoqKioNCiMjIE90cmFzIHBlcnNvbmFsaXphY2lvbmVzDQoNClNpLCBwb3Igb3RybyBsYWRvLCBzZSBxdWlzaWVyYSBjYW1iaWFyIGFsZ3VubyBkZSBlc29zIGF0cmlidXRvcyBwb3IgZGVmYXVsdCwgc2luIHF1ZSDDqXN0b3MgZGVwZW5kYW4gZGUgYWxndW5hIHZhcmlhYmxlLCBzZSBwdWVkZSBoYWNlciBzaSBzZSBlc3BlY2lmaWNhbiBmdWVyYSBkZWwgYGFlcygpYA0KDQpgYGB7ciBnZW9tX3BvaW50LWZpeGVkIGNvbG9yfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSksDQogICAgICAgICAgICAgY29sb3IgPSAiYmx1ZSIpDQpgYGANCg0KQ3VpZGFkbywgcG9ycXVlIHNpIHNlIHBvbmUgZGVudHJvIGRlbCBhZXMoKSBubyB2YSBhIGRhciBlbCByZXN1bHRhZG8gcXVlIGJ1c2NhbW9zOg0KDQpgYGB7ciBnZW9tX3BvaW50LWNvbG9yLXdyb25nLCBtZXNzYWdlPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gImluZGlhbnJlZDEiKSkgKw0KICBnZ3RpdGxlKCJEZWZpbmlyIGVsIGNvbG9yIGZpam8gZGVudHJvIGRlbCBhZXMoKSBwcm9kdWNlIGVycm9yZXMiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpLA0KICAgICAgICAgICAgIGNvbG9yID0gImJsdWUiLA0KICAgICAgICAgICAgIGZpbGwgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICBzaGFwZSA9IDIyLA0KICAgICAgICAgICAgIHNpemUgPSAyLA0KICAgICAgICAgICAgIGFscGhhID0gMC4yDQogICAgICAgICAgICAgKQ0KYGBgDQoNClRhbWJpw6luIHNlIHB1ZWRlbiBqdW50YXIgdmFyaW9zIGRlIGVzdG9zIGF0cmlidXRvcyBhbCBtaXNtbyB0aWVtcG8sIHNpIGVzbyBzZSBkZXNlYXJhOg0KDQpgYGB7ciBnZW9tX3BvaW50LWNvbCBzaGFwZSBzaXplLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTZ9DQpnZ3Bsb3QoZGF0YSA9IG1wZ19lZGl0YWRhMikgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjbGFzcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZHJ2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGN5bCksDQogICAgICAgICAgICAgYWxwaGEgPSAwLjcpDQpgYGANCg0KU2UgcHVlZGVuIGFzb2NpYXIgdmFyaWFzIGNhcmFjdGVyw61zdGljYXMgYSBsYSBtaXNtYSB2YXJpYWJsZToNCg0KYGBge3IgZ2VvbV9wb2ludC1jb2wgc2hhcGUgc2l6ZTIsIHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IG1wZ19lZGl0YWRhMikgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gaHd5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjbGFzcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gY2xhc3MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gY2xhc3MpLA0KICAgICAgICAgICAgIGFscGhhID0gMC43KQ0KYGBgDQoNCiMjIFZhcmlhcyBncsOhZmljYXMgZW4gdW5hIHNvbGEgY29uIGBwYXRjaHdvcmtgDQoNCkxvcyBncsOhZmljb3MgcXVlIHJlY2nDqW4gY3JlYW1vcyBwdWVkZW4gc2VyIGFsbWFjZW5hZG9zIGVuIHZhcmlhYmxlcy4gTGEgcGFxdWV0ZXLDrWEgcGF0Y2h3b3JrIG5vcyBwZXJtaXRlIGp1bnRhciBkb3MgbyBtw6FzIGdyw6FmaWNhcyBkZSBnZ3Bsb3QgZW4gdW5hIHNvbGEgaW1hZ2VuLiBSZXRvbWVtb3MgYWxndW5hcyBkZSBsYXMgZ3LDoWZpY2FzIGFudGVyaW9yZXMuDQoNCioqTk9UQToqKiAqRWwgbm9tYnJlIHNlIGVzY29nZSBhcmJpdHJhcmlhbWVudGUuKg0KDQpgYGB7ciBnZ3Bsb3RzLCBtZXNzYWdlPUZBTFNFfQ0KIyBMYXMgZ3LDoWZpY2FzIGEgcG9uZXIgZW4gdW5hIHNvbGEgaW1hZ2VuDQpnMSA8LSBnZ3Bsb3QoZGF0YSA9IG1wZ19lZGl0YWRhMikgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsNCiAgZ2d0aXRsZSgiTGEgZ3LDoWZpY2EgbcOhcyBiw6FzaWNhIikNCg0KZzIgPC0gZ2dwbG90KGRhdGEgPSBtcGdfZWRpdGFkYTIpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gY2xhc3MpKSsNCiAgZ2d0aXRsZSgiQ29sb3IgdmFyaWFibGUiKQ0KDQpnMyA8LSBnZ3Bsb3QoZGF0YSA9IG1wZ19lZGl0YWRhMikgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSksIGNvbG9yID0gImJsdWUiKSsNCiAgZ2d0aXRsZSgiQ29sb3IgZmlqbyIpDQoNCmc0IDwtIGdncGxvdChkYXRhID0gbXBnX2VkaXRhZGEyKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBod3ksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNsYXNzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSBkcnYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gY3lsKSwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKyANCiAgZ2d0aXRsZSgiQ29sLCBmb3JtYSB5IHRhbSB2YXIsIGFscGhhIGZpamEiKQ0KYGBgDQoNCkVsIGFjb21vZG8gc2UgcHVlZGUgZ3VhcmRhciBlbiB1bmEgdmFyaWFibGUgdGFtYmnDqW4uIENvbiBgcGF0Y2h3b3JrYCBlcyBiYXN0YW50ZSBpbnR1aXRpdmEgbGEgbWFuZXJhIGRlIGFjb21vZGFyIGxhcyBncsOhZmljYXMuDQoNCiogYCtgIHNpcnZlIHBhcmEgYWdyZWdhciBncsOhZmljb3MgZW4gZXNhIGzDrW5lYSAodGFtYmnDqW4gZnVuY2lvbmEgdXRpbGl6YXIgYHxgKS4NCg0KYGBge3J9DQpnMSArIGcyDQoNCmcxICsgZzIgKyBnMw0KDQpnMSArIGcyICsgZzMgKyBnNA0KDQpnMSB8IGcyIHwgZzMgfCBnNA0KYGBgDQoNCg0KKiBgL2Agc2lydmUgcGFyYSBjcmVhciB1bmEgbnVldmEgZmlsYS4NCg0KYGBge3IgcGF0Y2h3b3JrMSwgZmlnLmhlaWdodD0xMixmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9DQpmaWcxIDwtIGcxIC8NCiAgKGcyICsgZzMpIC8NCiAgZzQNCg0KZmlnMQ0KYGBgDQoNClNlIHB1ZWRlbiBhZ3JlZ2FyIHTDrXR1bG9zIHkgc3VidMOtdHVsb3MgZ2xvYmFsZXMgY29uIGBwbG90X2Fubm90YXRpb24oKWAuIFRhbWJpw6luLCBzZSBwdWVkZSBkZWphciBlc3BhY2lvcyBlbiBibGFuY28gdXNhbmRvIGBwbG90X3NwYWNlcigpYDoNCg0KYGBge3IgcGF0Y2h3b3JrMiwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9MTIsIHdhcm5pbmc9RkFMU0V9DQpmaWcxICsgDQogIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJHcsOhZmljYXMgY29uIGdncGxvdDIiLA0KICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiQ2FtYmlhbmRvIGxhIGVzdMOpdGljYSBkZSB2YXJpYXMgbWFuZXJhcyIpDQoNCihnMSArIHBsb3Rfc3BhY2VyKCkpIC8NCiAgKGc0KSAvDQogIChnMiArIGczKSArDQogIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJHcsOhZmljYXMgY29uIGdncGxvdDIiLA0KICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiT3RybyBhY29tb2RvIGRpc3RpbnRvIikNCg0KDQpgYGANCg0KDQpgYGB7cn0NCm1wZ19lZGl0YWRhMiAlPiUgDQogIGdncGxvdChhZXMoeCA9IG1hbnVmYWN0dXJlciwgeSA9IGRpc3BsKSkgKw0KICBnZW9tX2JveHBsb3QoKQ0KYGBgDQoNCg0KIyMgVXNvIGRlIGZhY2V0YXMgey50YWJzZXR9DQoNCk90cmEgb3BjacOzbiBwYXJhIHBlcnNvbmFsaXphciBncsOhZmljYXMgZXMgdXRpbGl6YXIgZmFjZXRhcy4gRXN0byBkaXZpZGUgbnVlc3RybyBncsOhZmljbyBlbiB2YXJpb3Mgc3ViZ3LDoWZpY29zLCBkZSBhY3VlcmRvIGEgYWxndW5hIHZhcmlhYmxlIGVzcGVjaWZpY2FkYS4NCg0KIyMjIGBmYWNldF93cmFwKClgDQoNClBhcmEgc2VwYXJhciBsb3Mgc3ViZ3LDoWZpY29zIGNvbiBiYXNlIGVuIHVuYSB2YXJpYWJsZToNCg0KYGBge3IgZmFjZXRfd3JhcCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD02LGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBod3ksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gZHJ2KSwNCiAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArIA0KICAgIGdndGl0bGUoIkZhY2V0YXMgcG9yIGNpbGluZHJhamUiKSArDQogIGZhY2V0X3dyYXAofiBjeWwpDQpgYGANCg0KIyMjIGBmYWNldF9ncmlkKClgDQoNCkxhcyBmYWNldGFzIHNlIHB1ZWRlbiBwb25lciBlbiBhbWJvcyBlamVzLCB1c2FuZG8gZG9zIHZhcmlhYmxlczoNCg0KYGBge3IgZmFjZXRfZ3JpZCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD02LGZpZy53aWR0aD04fQ0KZ2dwbG90KGRhdGEgPSBtcGcpICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGh3eSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY2xhc3MpLA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArIA0KICBnZ3RpdGxlKCJGYWNldGFzIHBvciB0cmFjY2nDs24geSBjaWxpbmRyYWplIikgKw0KICBmYWNldF9ncmlkKGN5bCB+IGRydikNCmBgYA0KDQojIyBHcsOhZmljYXMgZGUgbMOtbmVhcyB7LnRhYnNldH0NCg0KT3RybyB0aXBvIGRlIGdyw6FmaWNvIG11eSB1dGlsaXphZG8gZXMgZWwgZGUgbMOtbmVhcy4gVXNhcmVtb3Mgb3RybyBjb25qdW50byBkZSBkYXRvcyBwYXJhIGVzdG8uDQoNCmBgYHtyIGRhdG9zMiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCmRhdGEoImVjb25vbWljcyIpDQpgYGANCg0KU2UgcHVlZGUgYWNjZWRlciBhIGxhIGRvY3VtZW50YWNpw7NuIGRlIGVzdGUgZGF0YXNldCAoeSBkZSBjdWFscXVpZXIgZnVuY2nDs24pLCBhIHRyYXbDqXMgZGUgbGEgZnVuY2nDs24gYGhlbHAoKWA6DQoNCmBgYHtyIGhlbHAgZWNvbiwgZXZhbD1GQUxTRX0NCmhlbHAoImVjb25vbWljcyIpDQpgYGANCg0KDQpFc3RvcyBkYXRvcyBxdWUgaGVtb3MgdHJhYmFqYWRvIHNvbiBkZSB0aXBvIGB0aWJibGVgLiBQb2RlbW9zIG9ic2VydmFyIGxndW5hcyBkaWZlcmVuY2lhcyBlbnRyZSB1biBvYmpldG8gYHRpYmJsZWAgeSB1biBgZGF0YS5mcmFtZWAgdHJhZGljaW9uYWw6DQoNCiMjIyBUaWJibGUNCg0KVGUgbXVlc3RyYSBzb2xvIGxhcyBwcmltZXJhcyAxMCBmaWxhcywgYXPDrSBjb21vIGVsIHRpcG8gZGUgZGF0b3MgZGUgY2FkYSBjb2x1bW5hLiBUYW1iacOpbiB0ZSBkYSBlbiByZXN1bWVuIGxhIGRpbWVuc2nDs24gZGUgbGEgdGFibGEgKGZpbGFzIHggY29sdW1uYXMpLg0KYGBge3IgdGliYmxlLCBldmFsPUZBTFNFfQ0KZWNvbm9taWNzDQojIEEgdGliYmxlOiA1NzQgeCA2DQojICAgIGRhdGUgICAgICAgICBwY2UgICAgcG9wIHBzYXZlcnQgdWVtcG1lZCB1bmVtcGxveQ0KIyAgICA8ZGF0ZT4gICAgIDxkYmw+ICA8ZGJsPiAgIDxkYmw+ICAgPGRibD4gICAgPGRibD4NCiMgIDEgMTk2Ny0wNy0wMSAgNTA3LiAxOTg3MTIgICAgMTIuNiAgICAgNC41ICAgICAyOTQ0DQojICAyIDE5NjctMDgtMDEgIDUxMC4gMTk4OTExICAgIDEyLjYgICAgIDQuNyAgICAgMjk0NQ0KIyAgMyAxOTY3LTA5LTAxICA1MTYuIDE5OTExMyAgICAxMS45ICAgICA0LjYgICAgIDI5NTgNCiMgIDQgMTk2Ny0xMC0wMSAgNTEyLiAxOTkzMTEgICAgMTIuOSAgICAgNC45ICAgICAzMTQzDQojICA1IDE5NjctMTEtMDEgIDUxNy4gMTk5NDk4ICAgIDEyLjggICAgIDQuNyAgICAgMzA2Ng0KIyAgNiAxOTY3LTEyLTAxICA1MjUuIDE5OTY1NyAgICAxMS44ICAgICA0LjggICAgIDMwMTgNCiMgIDcgMTk2OC0wMS0wMSAgNTMxLiAxOTk4MDggICAgMTEuNyAgICAgNS4xICAgICAyODc4DQojICA4IDE5NjgtMDItMDEgIDUzNC4gMTk5OTIwICAgIDEyLjMgICAgIDQuNSAgICAgMzAwMQ0KIyAgOSAxOTY4LTAzLTAxICA1NDQuIDIwMDA1NiAgICAxMS43ICAgICA0LjEgICAgIDI4NzcNCiMgMTAgMTk2OC0wNC0wMSAgNTQ0ICAyMDAyMDggICAgMTIuMyAgICAgNC42ICAgICAyNzA5DQojIC4uLiB3aXRoIDU2NCBtb3JlIHJvd3MNCmBgYA0KDQojIyMgRGF0YS5mcmFtZQ0KDQpgYGB7ciBkYXRhLmZyYW1lLCBldmFsPUZBTFNFfQ0KYXMuZGF0YS5mcmFtZShlY29ub21pY3MpDQojICAgICAgICAgICBkYXRlICAgIHBjZSAgICBwb3AgcHNhdmVydCB1ZW1wbWVkIHVuZW1wbG95DQojIDEgICAxOTY3LTA3LTAxICA1MDYuNyAxOTg3MTIgICAgMTIuNiAgICAgNC41ICAgICAyOTQ0DQojIDIgICAxOTY3LTA4LTAxICA1MDkuOCAxOTg5MTEgICAgMTIuNiAgICAgNC43ICAgICAyOTQ1DQojIDMgICAxOTY3LTA5LTAxICA1MTUuNiAxOTkxMTMgICAgMTEuOSAgICAgNC42ICAgICAyOTU4DQojIDQgICAxOTY3LTEwLTAxICA1MTIuMiAxOTkzMTEgICAgMTIuOSAgICAgNC45ICAgICAzMTQzDQojIDUgICAxOTY3LTExLTAxICA1MTcuNCAxOTk0OTggICAgMTIuOCAgICAgNC43ICAgICAzMDY2DQojIDYgICAxOTY3LTEyLTAxICA1MjUuMSAxOTk2NTcgICAgMTEuOCAgICAgNC44ICAgICAzMDE4DQojIDcgICAxOTY4LTAxLTAxICA1MzAuOSAxOTk4MDggICAgMTEuNyAgICAgNS4xICAgICAyODc4DQojIDggICAxOTY4LTAyLTAxICA1MzMuNiAxOTk5MjAgICAgMTIuMyAgICAgNC41ICAgICAzMDAxDQojIDkgICAxOTY4LTAzLTAxICA1NDQuMyAyMDAwNTYgICAgMTEuNyAgICAgNC4xICAgICAyODc3DQojIDEwICAxOTY4LTA0LTAxICA1NDQuMCAyMDAyMDggICAgMTIuMyAgICAgNC42ICAgICAyNzA5DQojIDExICAxOTY4LTA1LTAxICA1NDkuOCAyMDAzNjEgICAgMTIuMCAgICAgNC40ICAgICAyNzQwDQojIDEyICAxOTY4LTA2LTAxICA1NTYuMyAyMDA1MzYgICAgMTEuNyAgICAgNC40ICAgICAyOTM4DQojIDEzICAxOTY4LTA3LTAxICA1NjMuMiAyMDA3MDYgICAgMTAuNyAgICAgNC41ICAgICAyODgzDQojIDE0ICAxOTY4LTA4LTAxICA1NjcuMCAyMDA4OTggICAgMTAuNSAgICAgNC4yICAgICAyNzY4DQojIDE1ICAxOTY4LTA5LTAxICA1NjguMiAyMDEwOTUgICAgMTAuNiAgICAgNC42ICAgICAyNjg2DQojIDE2ICAxOTY4LTEwLTAxICA1NzEuNiAyMDEyOTAgICAgMTAuOCAgICAgNC44ICAgICAyNjg5DQojIDE3ICAxOTY4LTExLTAxICA1NzYuNyAyMDE0NjYgICAgMTAuNiAgICAgNC40ICAgICAyNzE1DQojIDE4ICAxOTY4LTEyLTAxICA1NzYuNSAyMDE2MjEgICAgMTEuMSAgICAgNC40ICAgICAyNjg1DQojIDE5ICAxOTY5LTAxLTAxICA1ODMuNSAyMDE3NjAgICAgMTAuMyAgICAgNC40ICAgICAyNzE4DQojIDIwICAxOTY5LTAyLTAxICA1ODguNyAyMDE4ODEgICAgIDkuNyAgICAgNC45ICAgICAyNjkyDQojIDIxICAxOTY5LTAzLTAxICA1ODguOSAyMDIwMjMgICAgMTAuMiAgICAgNC4wICAgICAyNzEyDQojIDIyICAxOTY5LTA0LTAxICA1OTMuOSAyMDIxNjEgICAgIDkuNyAgICAgNC4wICAgICAyNzU4DQojIDIzICAxOTY5LTA1LTAxICA2MDAuMyAyMDIzMzEgICAgMTAuMSAgICAgNC4yICAgICAyNzEzDQojIDI0ICAxOTY5LTA2LTAxICA2MDAuOSAyMDI1MDcgICAgMTEuMSAgICAgNC40ICAgICAyODE2DQojIDI1ICAxOTY5LTA3LTAxICA2MDIuNyAyMDI2NzcgICAgMTEuOCAgICAgNC40ICAgICAyODY4DQojIDI2ICAxOTY5LTA4LTAxICA2MDkuOSAyMDI4NzcgICAgMTEuNSAgICAgNC40ICAgICAyODU2DQojIDI3ICAxOTY5LTA5LTAxICA2MTMuMiAyMDMwOTAgICAgMTEuNiAgICAgNC43ICAgICAzMDQwDQojIDI4ICAxOTY5LTEwLTAxICA2MTguNSAyMDMzMDIgICAgMTEuNCAgICAgNC41ICAgICAzMDQ5DQojIDI5ICAxOTY5LTExLTAxICA2MjAuNSAyMDM1MDAgICAgMTEuNiAgICAgNC44ICAgICAyODU2DQojIDMwICAxOTY5LTEyLTAxICA2MjIuOCAyMDM2NzUgICAgMTEuOCAgICAgNC42ICAgICAyODg0DQojIDMxICAxOTcwLTAxLTAxICA2MjguNyAyMDM4NDkgICAgMTEuOCAgICAgNC42ICAgICAzMjAxDQojIDMyICAxOTcwLTAyLTAxICA2MzQuMCAyMDQwMDggICAgMTEuNyAgICAgNC41ICAgICAzNDUzDQojIDMzICAxOTcwLTAzLTAxICA2MzIuMyAyMDQxNTYgICAgMTIuNCAgICAgNC42ICAgICAzNjM1DQojIDM0ICAxOTcwLTA0LTAxICA2MzYuMCAyMDQ0MDEgICAgMTMuMyAgICAgNC4xICAgICAzNzk3DQojIDM1ICAxOTcwLTA1LTAxICA2NDIuNCAyMDQ2MDcgICAgMTIuNCAgICAgNC43ICAgICAzOTE5DQojIDM2ICAxOTcwLTA2LTAxICA2NDYuMyAyMDQ4MzAgICAgMTIuMyAgICAgNC45ICAgICA0MDcxDQojIDM3ICAxOTcwLTA3LTAxICA2NDguNSAyMDUwNTIgICAgMTMuNSAgICAgNS4xICAgICA0MTc1DQojIDM4ICAxOTcwLTA4LTAxICA2NTIuOSAyMDUyOTUgICAgMTMuNCAgICAgNS40ICAgICA0MjU2DQojIDM5ICAxOTcwLTA5LTAxICA2NTkuMSAyMDU1NDAgICAgMTIuOSAgICAgNS4yICAgICA0NDU2DQojIDQwICAxOTcwLTEwLTAxICA2NTguMyAyMDU3ODggICAgMTMuMSAgICAgNS4yICAgICA0NTkxDQojIDQxICAxOTcwLTExLTAxICA2NTYuNiAyMDYwMjQgICAgMTMuNiAgICAgNS42ICAgICA0ODk4DQojIDQyICAxOTcwLTEyLTAxICA2NjUuNiAyMDYyMzggICAgMTMuMiAgICAgNS45ICAgICA1MDc2DQojIDQzICAxOTcxLTAxLTAxICA2NzYuMSAyMDY0NjYgICAgMTMuMyAgICAgNi4yICAgICA0OTg2DQojIDQ0ICAxOTcxLTAyLTAxICA2NzkuNCAyMDY2NjggICAgMTMuMyAgICAgNi4zICAgICA0OTAzDQojIDQ1ICAxOTcxLTAzLTAxICA2ODIuMCAyMDY4NTUgICAgMTMuNSAgICAgNi40ICAgICA0OTg3DQojIDQ2ICAxOTcxLTA0LTAxICA2ODguOCAyMDcwNjUgICAgMTMuMiAgICAgNi41ICAgICA0OTU5DQojIDQ3ICAxOTcxLTA1LTAxICA2OTEuMSAyMDcyNjAgICAgMTMuNiAgICAgNi43ICAgICA0OTk2DQojIDQ4ICAxOTcxLTA2LTAxICA2OTkuOCAyMDc0NjIgICAgMTQuNyAgICAgNS43ICAgICA0OTQ5DQojIDQ5ICAxOTcxLTA3LTAxICA2OTguOSAyMDc2NjEgICAgMTMuOCAgICAgNi4yICAgICA1MDM1DQojIDUwICAxOTcxLTA4LTAxICA3MDQuOSAyMDc4ODEgICAgMTMuNiAgICAgNi40ICAgICA1MTM0DQojIDUxICAxOTcxLTA5LTAxICA3MTMuMCAyMDgxMTQgICAgMTMuMyAgICAgNS44ICAgICA1MDQyDQojIDUyICAxOTcxLTEwLTAxICA3MTUuOCAyMDgzNDUgICAgMTMuMyAgICAgNi41ICAgICA0OTU0DQojIDUzICAxOTcxLTExLTAxICA3MjAuOSAyMDg1NTUgICAgMTMuMSAgICAgNi40ICAgICA1MTYxDQojIDU0ICAxOTcxLTEyLTAxICA3MjguNCAyMDg3NDAgICAgMTMuMCAgICAgNi4yICAgICA1MTU0DQojIDU1ICAxOTcyLTAxLTAxICA3MzEuNSAyMDg5MTcgICAgMTIuNSAgICAgNi4yICAgICA1MDE5DQojIDU2ICAxOTcyLTAyLTAxICA3MzYuMiAyMDkwNjEgICAgMTIuOCAgICAgNi42ICAgICA0OTI4DQojIDU3ICAxOTcyLTAzLTAxICA3NDkuMiAyMDkyMTIgICAgMTEuOCAgICAgNi42ICAgICA1MDM4DQojIDU4ICAxOTcyLTA0LTAxICA3NTIuNSAyMDkzODYgICAgMTEuNSAgICAgNi43ICAgICA0OTU5DQojIDU5ICAxOTcyLTA1LTAxICA3NTguMCAyMDk1NDUgICAgMTEuNyAgICAgNi42ICAgICA0OTIyDQojIDYwICAxOTcyLTA2LTAxICA3NjEuNiAyMDk3MjUgICAgMTEuNyAgICAgNS40ICAgICA0OTIzDQojIDYxICAxOTcyLTA3LTAxICA3NjkuOSAyMDk4OTYgICAgMTEuNyAgICAgNi4xICAgICA0OTEzDQojIDYyICAxOTcyLTA4LTAxICA3NzYuMyAyMTAwNzUgICAgMTIuMCAgICAgNi4wICAgICA0OTM5DQojIDYzICAxOTcyLTA5LTAxICA3ODEuMSAyMTAyNzggICAgMTIuMiAgICAgNS42ICAgICA0ODQ5DQojIDY0ICAxOTcyLTEwLTAxICA3OTQuOSAyMTA0NzkgICAgMTMuMCAgICAgNS43ICAgICA0ODc1DQojIDY1ICAxOTcyLTExLTAxICA4MDAuNSAyMTA2NTYgICAgMTMuNiAgICAgNS43ICAgICA0NjAyDQojIDY2ICAxOTcyLTEyLTAxICA4MDYuMSAyMTA4MjEgICAgMTMuNyAgICAgNi4xICAgICA0NTQzDQojIDY3ICAxOTczLTAxLTAxICA4MTYuNSAyMTA5ODUgICAgMTIuNCAgICAgNS43ICAgICA0MzI2DQojIDY4ICAxOTczLTAyLTAxICA4MjUuOCAyMTExMjAgICAgMTIuNSAgICAgNS4yICAgICA0NDUyDQojIDY5ICAxOTczLTAzLTAxICA4MzIuOCAyMTEyNTQgICAgMTIuNyAgICAgNS41ICAgICA0Mzk0DQojIDcwICAxOTczLTA0LTAxICA4MzUuNyAyMTE0MjAgICAgMTMuMiAgICAgNS4wICAgICA0NDU5DQojIDcxICAxOTczLTA1LTAxICA4NDEuNiAyMTE1NzcgICAgMTMuMiAgICAgNC45ICAgICA0MzI5DQojIDcyICAxOTczLTA2LTAxICA4NDQuMyAyMTE3NDYgICAgMTMuNiAgICAgNS4wICAgICA0MzYzDQojIDczICAxOTczLTA3LTAxICA4NTQuMSAyMTE5MDkgICAgMTMuMiAgICAgNS4yICAgICA0MzA1DQojIDc0ICAxOTczLTA4LTAxICA4NTMuMyAyMTIwOTIgICAgMTMuOSAgICAgNC45ICAgICA0MzA1DQojIDc1ICAxOTczLTA5LTAxICA4NjkuMiAyMTIyODkgICAgMTMuMSAgICAgNS40ICAgICA0MzUwDQojIDc2ICAxOTczLTEwLTAxICA4NjguMiAyMTI0NzUgICAgMTQuNCAgICAgNS41ICAgICA0MTQ0DQojIDc3ICAxOTczLTExLTAxICA4NzYuOSAyMTI2MzQgICAgMTQuNCAgICAgNS4xICAgICA0Mzk2DQojIDc4ICAxOTczLTEyLTAxICA4NzYuNiAyMTI3ODUgICAgMTQuOCAgICAgNC43ICAgICA0NDg5DQojIDc5ICAxOTc0LTAxLTAxICA4ODQuNSAyMTI5MzIgICAgMTQuMyAgICAgNS4wICAgICA0NjQ0DQojIDgwICAxOTc0LTAyLTAxICA4ODkuNyAyMTMwNzQgICAgMTQuMiAgICAgNS4xICAgICA0NzMxDQojIDgxICAxOTc0LTAzLTAxICA5MDEuNCAyMTMyMTEgICAgMTMuNCAgICAgNC44ICAgICA0NjM0DQojIDgyICAxOTc0LTA0LTAxICA5MTAuOCAyMTMzNjEgICAgMTMuMSAgICAgNS4wICAgICA0NjE4DQojIDgzICAxOTc0LTA1LTAxICA5MjIuNCAyMTM1MTMgICAgMTIuOCAgICAgNC42ICAgICA0NzA1DQojIDg0ICAxOTc0LTA2LTAxICA5MjguMCAyMTM2ODYgICAgMTIuOCAgICAgNS4zICAgICA0OTI3DQojIDg1ICAxOTc0LTA3LTAxICA5MzcuOSAyMTM4NTQgICAgMTIuOCAgICAgNS43ICAgICA1MDYzDQojIDg2ICAxOTc0LTA4LTAxICA5NTQuOCAyMTQwNDIgICAgMTIuMSAgICAgNS4wICAgICA1MDIyDQojIDg3ICAxOTc0LTA5LTAxICA5NTUuMSAyMTQyNDYgICAgMTIuOSAgICAgNS4zICAgICA1NDM3DQojIDg4ICAxOTc0LTEwLTAxICA5NTkuMiAyMTQ0NTEgICAgMTMuNCAgICAgNS41ICAgICA1NTIzDQojIDg5ICAxOTc0LTExLTAxICA5NTYuMiAyMTQ2MjUgICAgMTMuOCAgICAgNS4yICAgICA2MTQwDQojIDkwICAxOTc0LTEyLTAxICA5NjEuOCAyMTQ3ODIgICAgMTQuMCAgICAgNS43ICAgICA2NjM2DQojIDkxICAxOTc1LTAxLTAxICA5NzUuNiAyMTQ5MzEgICAgMTMuMiAgICAgNi4zICAgICA3NTAxDQojIDkyICAxOTc1LTAyLTAxICA5ODkuNCAyMTUwNjUgICAgMTIuNSAgICAgNy4xICAgICA3NTIwDQojIDkzICAxOTc1LTAzLTAxICA5OTAuNiAyMTUxOTggICAgMTIuNyAgICAgNy4yICAgICA3OTc4DQojIDk0ICAxOTc1LTA0LTAxICA5OTUuMCAyMTUzNTMgICAgMTQuMiAgICAgOC43ICAgICA4MjEwDQojIDk1ICAxOTc1LTA1LTAxIDEwMTguOSAyMTU1MjMgICAgMTcuMyAgICAgOS40ICAgICA4NDMzDQojIDk2ICAxOTc1LTA2LTAxIDEwMjYuOCAyMTU3NjggICAgMTQuMyAgICAgOC44ICAgICA4MjIwDQojIDk3ICAxOTc1LTA3LTAxIDEwMzkuOCAyMTU5NzMgICAgMTIuNiAgICAgOC42ICAgICA4MTI3DQojIDk4ICAxOTc1LTA4LTAxIDEwNDcuMCAyMTYxOTUgICAgMTMuMCAgICAgOS4yICAgICA3OTI4DQojIDk5ICAxOTc1LTA5LTAxIDEwNTQuOCAyMTYzOTMgICAgMTMuMCAgICAgOS4yICAgICA3OTIzDQojIDEwMCAxOTc1LTEwLTAxIDEwNjAuOSAyMTY1ODcgICAgMTMuNCAgICAgOC42ICAgICA3ODk3DQojIDEwMSAxOTc1LTExLTAxIDEwNzUuOCAyMTY3NzEgICAgMTIuNyAgICAgOS41ICAgICA3Nzk0DQojIDEwMiAxOTc1LTEyLTAxIDEwOTIuMSAyMTY5MzEgICAgMTIuMCAgICAgOS4wICAgICA3NzQ0DQojIDEwMyAxOTc2LTAxLTAxIDExMDcuMSAyMTcwOTUgICAgMTEuNyAgICAgOS4wICAgICA3NTM0DQojIDEwNCAxOTc2LTAyLTAxIDExMDcuNyAyMTcyNDkgICAgMTIuMyAgICAgOC4yICAgICA3MzI2DQojIDEwNSAxOTc2LTAzLTAxIDExMTQuOSAyMTczODEgICAgMTIuMiAgICAgOC43ICAgICA3MjMwDQojIDEwNiAxOTc2LTA0LTAxIDExMjUuNCAyMTc1MjggICAgMTEuNyAgICAgOC4yICAgICA3MzMwDQojIDEwNyAxOTc2LTA1LTAxIDExMjIuNyAyMTc2ODUgICAgMTIuMyAgICAgOC4zICAgICA3MDUzDQojIDEwOCAxOTc2LTA2LTAxIDExNDAuNSAyMTc4NjEgICAgMTEuNCAgICAgNy44ICAgICA3MzIyDQojIDEwOSAxOTc2LTA3LTAxIDExNDkuNiAyMTgwMzUgICAgMTEuNyAgICAgNy43ICAgICA3NDkwDQojIDExMCAxOTc2LTA4LTAxIDExNTguMCAyMTgyMzMgICAgMTEuNyAgICAgNy45ICAgICA3NTE4DQojIDExMSAxOTc2LTA5LTAxIDExNjguOCAyMTg0NDAgICAgMTEuNCAgICAgNy44ICAgICA3MzgwDQojIDExMiAxOTc2LTEwLTAxIDExNzYuOCAyMTg2NDQgICAgMTEuMSAgICAgNy43ICAgICA3NDMwDQojIDExMyAxOTc2LTExLTAxIDExODkuMCAyMTg4MzQgICAgMTEuNCAgICAgOC40ICAgICA3NjIwDQojIDExNCAxOTc2LTEyLTAxIDEyMTEuNSAyMTkwMDYgICAgMTAuNiAgICAgOC4wICAgICA3NTQ1DQojIDExNSAxOTc3LTAxLTAxIDEyMTUuMCAyMTkxNzkgICAgMTAuNiAgICAgNy41ICAgICA3MjgwDQojIDExNiAxOTc3LTAyLTAxIDEyMzEuMyAyMTkzNDQgICAgIDkuMyAgICAgNy4yICAgICA3NDQzDQojIDExNyAxOTc3LTAzLTAxIDEyMzguMyAyMTk1MDQgICAgMTAuNSAgICAgNy4yICAgICA3MzA3DQojIDExOCAxOTc3LTA0LTAxIDEyNDcuMyAyMTk2ODQgICAgMTAuNSAgICAgNy4zICAgICA3MDU5DQojIDExOSAxOTc3LTA1LTAxIDEyNTcuMSAyMTk4NTkgICAgMTAuMyAgICAgNy45ICAgICA2OTExDQojIDEyMCAxOTc3LTA2LTAxIDEyNjMuNiAyMjAwNDYgICAgMTAuNiAgICAgNi4yICAgICA3MTM0DQojIDEyMSAxOTc3LTA3LTAxIDEyODAuNSAyMjAyMzkgICAgMTAuNSAgICAgNy4xICAgICA2ODI5DQojIDEyMiAxOTc3LTA4LTAxIDEyODUuNyAyMjA0NTggICAgMTAuOSAgICAgNy4wICAgICA2OTI1DQojIDEyMyAxOTc3LTA5LTAxIDEyOTQuNSAyMjA2ODggICAgMTEuMSAgICAgNi43ICAgICA2NzUxDQojIDEyNCAxOTc3LTEwLTAxIDEzMTEuNCAyMjA5MDQgICAgMTEuMCAgICAgNi45ICAgICA2NzYzDQojIDEyNSAxOTc3LTExLTAxIDEzMjcuMCAyMjExMDkgICAgMTEuMiAgICAgNy4wICAgICA2ODE1DQojIDEyNiAxOTc3LTEyLTAxIDEzMzYuMCAyMjEzMDMgICAgMTEuNCAgICAgNi44ICAgICA2Mzg2DQojIDEyNyAxOTc4LTAxLTAxIDEzMjkuNSAyMjE0NzcgICAgMTEuOSAgICAgNi41ICAgICA2NDg5DQojIDEyOCAxOTc4LTAyLTAxIDEzNTUuMSAyMjE2MjkgICAgMTEuMSAgICAgNi43ICAgICA2MzE4DQojIDEyOSAxOTc4LTAzLTAxIDEzNzcuNSAyMjE3OTIgICAgMTEuMCAgICAgNi4yICAgICA2MzM3DQojIDEzMCAxOTc4LTA0LTAxIDEzOTYuNCAyMjE5OTEgICAgMTAuOCAgICAgNi4xICAgICA2MTgwDQojIDEzMSAxOTc4LTA1LTAxIDE0MTIuMCAyMjIxNzYgICAgMTAuMyAgICAgNS43ICAgICA2MTI3DQojIDEzMiAxOTc4LTA2LTAxIDE0MjUuOCAyMjIzNzkgICAgMTAuMCAgICAgNi4wICAgICA2MDI4DQojIDEzMyAxOTc4LTA3LTAxIDE0MjYuOCAyMjI1ODUgICAgMTAuOSAgICAgNS44ICAgICA2MzA5DQojIDEzNCAxOTc4LTA4LTAxIDE0NDcuMCAyMjI4MDUgICAgMTAuNSAgICAgNS44ICAgICA2MDgwDQojIDEzNSAxOTc4LTA5LTAxIDE0NTIuOSAyMjMwNTMgICAgMTAuNiAgICAgNS42ICAgICA2MTI1DQojIDEzNiAxOTc4LTEwLTAxIDE0NjYuOSAyMjMyNzEgICAgMTAuNyAgICAgNS45ICAgICA1OTQ3DQojIDEzNyAxOTc4LTExLTAxIDE0ODAuNiAyMjM0NzcgICAgMTAuNSAgICAgNS41ICAgICA2MDc3DQojIDEzOCAxOTc4LTEyLTAxIDE0OTYuNSAyMjM2NzAgICAgMTAuNCAgICAgNS42ICAgICA2MjI4DQojIDEzOSAxOTc5LTAxLTAxIDE1MDIuNCAyMjM4NjUgICAgMTEuMSAgICAgNS45ICAgICA2MTA5DQojIDE0MCAxOTc5LTAyLTAxIDE1MTcuOCAyMjQwNTMgICAgMTEuMSAgICAgNS45ICAgICA2MTczDQojIDE0MSAxOTc5LTAzLTAxIDE1MzEuMiAyMjQyMzUgICAgMTEuMiAgICAgNS45ICAgICA2MTA5DQojIDE0MiAxOTc5LTA0LTAxIDE1MzguNCAyMjQ0MzggICAgMTEuMCAgICAgNS40ICAgICA2MDY5DQojIDE0MyAxOTc5LTA1LTAxIDE1NTguOCAyMjQ2MzIgICAgMTAuMyAgICAgNS42ICAgICA1ODQwDQojIDE0NCAxOTc5LTA2LTAxIDE1NzUuNyAyMjQ4NDMgICAgIDkuOSAgICAgNS42ICAgICA1OTU5DQojIDE0NSAxOTc5LTA3LTAxIDE1ODYuMSAyMjUwNTUgICAgMTAuNiAgICAgNS45ICAgICA1OTk2DQojIDE0NiAxOTc5LTA4LTAxIDE2MTUuNiAyMjUyOTUgICAgIDkuNyAgICAgNC44ICAgICA2MzIwDQojIDE0NyAxOTc5LTA5LTAxIDE2MzMuOSAyMjU1NDcgICAgIDkuNCAgICAgNS41ICAgICA2MTkwDQojIDE0OCAxOTc5LTEwLTAxIDE2NDEuNiAyMjU4MDEgICAgIDkuNyAgICAgNS41ICAgICA2Mjk2DQojIDE0OSAxOTc5LTExLTAxIDE2NTcuMyAyMjYwMjcgICAgIDkuNyAgICAgNS4zICAgICA2MjM4DQojIDE1MCAxOTc5LTEyLTAxIDE2NjYuMyAyMjYyNDMgICAgMTAuMSAgICAgNS43ICAgICA2MzI1DQojIDE1MSAxOTgwLTAxLTAxIDE2OTcuMyAyMjY0NTEgICAgIDkuOSAgICAgNS4zICAgICA2NjgzDQojIDE1MiAxOTgwLTAyLTAxIDE3MDEuNCAyMjY2NTYgICAgMTAuMSAgICAgNS44ICAgICA2NzAyDQojIDE1MyAxOTgwLTAzLTAxIDE3MDguMiAyMjY4NDkgICAgMTAuMiAgICAgNi4wICAgICA2NzI5DQojIDE1NCAxOTgwLTA0LTAxIDE2OTUuMiAyMjcwNjEgICAgMTEuMyAgICAgNS44ICAgICA3MzU4DQojIDE1NSAxOTgwLTA1LTAxIDE3MDAuMSAyMjcyNTEgICAgMTEuNCAgICAgNS43ICAgICA3OTg0DQojIDE1NiAxOTgwLTA2LTAxIDE3MTguOCAyMjc1MjIgICAgMTEuMiAgICAgNi40ICAgICA4MDk4DQojIDE1NyAxOTgwLTA3LTAxIDE3NDcuMSAyMjc3MjYgICAgMTEuMyAgICAgNy4wICAgICA4MzYzDQojIDE1OCAxOTgwLTA4LTAxIDE3NjMuOCAyMjc5NTMgICAgMTEuMyAgICAgNy41ICAgICA4MjgxDQojIDE1OSAxOTgwLTA5LTAxIDE3ODAuNSAyMjgxODYgICAgMTEuNyAgICAgNy43ICAgICA4MDIxDQojIDE2MCAxOTgwLTEwLTAxIDE4MTcuMSAyMjg0MTcgICAgMTEuMyAgICAgNy41ICAgICA4MDg4DQojIDE2MSAxOTgwLTExLTAxIDE4MjYuOCAyMjg2MTIgICAgMTEuNiAgICAgNy43ICAgICA4MDIzDQojIDE2MiAxOTgwLTEyLTAxIDE4NTEuNyAyMjg3NzkgICAgMTEuNCAgICAgNy41ICAgICA3NzE4DQojIDE2MyAxOTgxLTAxLTAxIDE4NzAuMCAyMjg5MzcgICAgMTAuOSAgICAgNy40ICAgICA4MDcxDQojIDE2NCAxOTgxLTAyLTAxIDE4ODQuMiAyMjkwNzEgICAgMTAuOCAgICAgNy4xICAgICA4MDUxDQojIDE2NSAxOTgxLTAzLTAxIDE5MDIuOSAyMjkyMjQgICAgMTAuOCAgICAgNy4xICAgICA3OTgyDQojIDE2NiAxOTgxLTA0LTAxIDE5MDQuNCAyMjk0MDMgICAgMTAuOSAgICAgNy40ICAgICA3ODY5DQojICBbIHJlYWNoZWQgJ21heCcgLyBnZXRPcHRpb24oIm1heC5wcmludCIpIC0tIG9taXR0ZWQgNDA4IHJvd3MgXQ0KYGBgDQoNCiMjIHstfQ0KDQoqKioNCg0KR3JhZmlxdWVtb3MgZWwgZGVzZW1wbGVvIGEgbG8gbGFyZ28gZGVsIHRpZW1wby4NCg0KYGBge3IgZ2VvbV9saW5lLCBtZXNzYWdlPUZBTFNFfQ0KZ2dwbG90KGVjb25vbWljcywNCiAgICAgICBhZXMoeCA9IGRhdGUsIHkgPSB1bmVtcGxveSkpICsgDQogIGdlb21fbGluZSgpDQpgYGANCg0KRmlsdHJhbmRvIGxvcyBkYXRvcyB5IGHDsWFkaWVuZG8gZG9zIGNhcGFzIGRlIGdyw6FmaWNvcyAocHVudG9zIHkgbMOtbmVhcyk6DQoNCmBgYHtyIGdlb21fbGluZSArIHBvaW50LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KGVjb25vbWljcyAlPiUgZmlsdGVyKHllYXIoZGF0ZSk+PTIwMDYpLA0KICAgICAgIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95KSkgKyANCiAgZ2VvbV9saW5lKGNvbG9yID0gInJlZCIpICsgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0iZm9yZXN0Z3JlZW4iKQ0KYGBgDQpTZXLDrWEgZXhhY3RhbWVudGUgZWwgbWlzbW8gcmVzdWx0YWRvIHNpIGRlZmluaW1vcyBlbCBgYWVzKClgIGRlbnRybyBkZSBjYWRhIHVubyBkZSBsb3MgYGdlb21zYDoNCg0KYGBge3IgZ2VvbV9saW5lICsgcG9pbnQgYWVzIGluZGVwZW5kZW50fQ0KZ2dwbG90KGVjb25vbWljcyAlPiUgZmlsdGVyKHllYXIoZGF0ZSk+PTIwMDYpKSArIA0KICBnZW9tX2xpbmUoYWVzKHggPSBkYXRlLCB5ID0gdW5lbXBsb3kpLCBjb2xvciA9ICJyZWQiKSArIA0KICBnZW9tX3BvaW50KGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95KSwgc2l6ZSA9IDEsIGNvbG9yID0iZm9yZXN0Z3JlZW4iKQ0KYGBgDQoNClNlIHB1ZWRlbiBjcmVhciBzdXMgcHJvcGlhcyBgdGliYmxlc2AgZGlyZWN0YW1lbnRlIGVuICoqUioqIGNvbiBsYSBmdW5jacOzbiBgdGliYmxlKClgOg0KDQoNCmBgYHtyfQ0KdGliYmxlKGZlY2hhID0gYygiMzEgYXVnIDIwIiwiMS1zZXAtMjAiLCIwMi85LzIwMjAiKSwNCiAgICAgICBkb2xhciA9IGMoMjQsMjQuMywyNSksDQogICAgICAgYGRpYSBjYWx1cm9zb2AgPSBjKDEsIDAsIDEpKSAlPiUNCiAgbXV0YXRlKGZlY2hhID0gZG15KGZlY2hhKSwgDQogICAgICAgICBgZGlhIGNhbHVyb3NvYCA9IGFzLmludGVnZXIoYGRpYSBjYWx1cm9zb2ApLA0KICAgICAgICAgYGRpYSBjYWx1cm9zbyAyYCA9IGFzLmxvZ2ljYWwoYGRpYSBjYWx1cm9zb2ApLA0KICAgICAgICAgYGRpYSBjYWx1cm9zbyAzYCA9IGFzX2ZhY3RvcihgZGlhIGNhbHVyb3NvYCkpDQoNCiMgRXN0byBtYXJjYXLDrWEgdW4gZXJyb3I6DQojIDIgPC0gNA0KIyBTZSBwdWVkZSBoYWNlciBlc3RvLCBwZXJvIE5PIGVzIHJlY29tZW5kYWJsZQ0KYDJgIDwtIDQNCmAyYA0KYGBgDQoNCg0KIyBUcmFuc2Zvcm1hY2nDs24gZGUgZGF0b3MgY29uIGBkcGx5cmANCg0KVXRpbGl6YXJlbW9zIGxvcyBkYXRvcyBkZSBgZ2FwbWluZGVyYCBwYXJhIHJldmlzYXIgdmFyaW9zIGVqZW1wbG9zLiBFeHBsb3JhbmRvIGxhIHRhYmxhLCB2ZW1vcyBxdWUgY29udGllbmUgMSw3MDQgZmlsYXMgY29uIDYgY29sdW1uYXM6DQoNCiogUGHDrXMgYGNvdW50cnlgDQoqIENvbnRpbmVudGUgYGNvbnRpbmVudGANCiogQcOxbyBgeWVhcmANCiogRXNwZXJhbnphIGRlIHZpZGEgKGVuIGHDsW9zKSBgbGlmZUV4cGANCiogUG9ibGFjacOzbiBgcG9wYA0KKiBQSUIgcGVyIGPDoXBpdGEgKGVuIFVTRCwgYWp1c3RhZG9zIHBvciBsYSBpbmZsYWNpw7NuKSBgZ2RwUGVyY2FwYA0KDQpgYGB7ciBnYXBtaW5kZXJ9DQpkYXRhKGdhcG1pbmRlcikNCmdhcG1pbmRlcg0KDQpnYXBtaW5kZXIgJT4lIA0KICBkaXN0aW5jdChjb3VudHJ5KSAlPiUgDQogIG5yb3coKQ0KDQojIGxldmVscyhnYXBtaW5kZXIkY291bnRyeSkNCmBgYA0KDQpTaSBxdWlzacOpcmFtb3MgZmlsdHJhciBsYSB0YWJsYSBwYXJhIG1hbnRlbmVyIHPDs2xvIGxvcyBwYcOtc2VzIGFzacOhdGljb3MsIGxvIHBvZHLDrWFtb3MgbG9ncmFyIGNvbiBlbCB2ZXJibyBgZmlsdGVyKClgLiBPcGNpb25hbG1lbnRlLCBwb2Ryw61hbW9zIHZhbGlkYXIgY29uIGBkaXN0aW5jdCgpYCBzaSBudWVzdHJvIGZpbHRybyBsb2dyw7MgZWwgb2JqZXRpdm86DQoNCmBgYHtyIGdhcCBmaWx0ZXIgY29udGluZW50fQ0KIyBQYXJhIHF1ZWRhcm5vcyBzb2xvIGNvbiBwYcOtc2VzIGFzacOhdGljb3MNCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb250aW5lbnQgPT0gIkFzaWEiKQ0KIyBWYWxpZGFjacOzbg0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQXNpYSIpICU+JSANCiAgZGlzdGluY3QoY29udGluZW50KQ0KDQpnYXBtaW5kZXIgJT4lIA0KICBkaXN0aW5jdChjb250aW5lbnQpDQpgYGANCg0KVmVtb3MgcXVlIGxhcyBmaWxhcyBkZSBsYSB0YWJsYSBzZSByZWR1amVyb24gKGEgMzk2KSB5IHF1ZSwgZWZlY3RpdmFtZW50ZSwgbG9ncmFtb3MgZWwgb2JqZXRpdm8gZGUgbWFudGVuZXIgcHVyb3MgcGHDrXNlcyBkZSBBc2lhLg0KDQpQb2RlbW9zIG9yZGVuYXIgdW5hIHRhYmxhIGNvbiByZXNwZWN0byBhIHVuYSBkZSBzdXMgdmFyaWFibGVzIGNvbiBgYXJyYW5nZSgpYC4gUG9yIGRlZsOhdWx0LCBlbCBvcmRlbiBzZXLDoSBhc2NlbmRlbnRlLiBTaSBzZSBkZXNlYSBlbiBvcmRlbiBkZXNjZW5kZW50ZSwgYWdyZWdhbW9zIGBkZXNjKClgLiBQcm9iZW1vcyBtb3N0cmFuZG8gYSBsb3MgcGHDrXNlcyBxdWUgdGllbmVuIGxhIG1heW9yIHBvYmxhY2nDs24gZW4gZWwgYcOxbyAyMDA3Lg0KDQpgYGB7ciBnYXAgYXJyYW5nZWR9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwb3ApKQ0KYGBgDQpQYXJhIHF1ZWRhcm5vcyBjb24gbG9zIGHDsW9zIGEgcGFydGlyIGRlIDE5OTcuDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgPj0gMTk5NykNCmBgYA0KDQpQZXJvIHNpIHF1aXNpw6lyYW1vcyBxdWVkYXJub3MgY29uIGxvcyBhw7FvcyAxOTUyLCAxOTcyLCAyMDAyLCAyMDA3LCDCv2PDs21vIGxvIHBvZHLDrWFtb3MgaGFjZXI/DQoNCkVzdG8gbm8gZnVuY2lvbmFyw61hIGNvbW8gZXNwZXJhbW9zOg0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDE5NTIsDQogICAgICAgICB5ZWFyID09IDE5NzIsDQogICAgICAgICB5ZWFyID09IDIwMDIsDQogICAgICAgICB5ZWFyID09IDIwMDcpDQoNCiMgRXMgbG8gbWlzbW8gcXVlIHNpIGhpY2nDqXJhbW9zIGVzdG86DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAxOTUyKSAlPiUgDQogIGZpbHRlcih5ZWFyID09IDE5NzIpICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMjAwMikgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KQ0KYGBgDQpFc3RvIG1hcmNhIGVycm9yLCBwb3JxdWUgZGVzcHXDqXMgZGUgY2FkYSBjb21hIGVzIG90cmEgY29uZGljacOzbiBkaXN0aW50YSBxdWUgKipSKiogZXZhbMO6YS4NCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMTk1MiwxOTcyLDIwMDIsMjAwNykNCmBgYA0KRXN0byBubyBkYSBlcnJvciwgcGVybyBubyBlcyBlbCByZXN1bHRhZG8gcXVlIGJ1c2NhbW9zLg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSBjKDE5NTIsMTk3MiwyMDAyLDIwMDcpKQ0KYGBgDQoNCg0KDQpMbyBwb2Ryw61hbW9zIGxvZ3JhciBjb24gbGEgZnVuY2nDs24gYCVpbiVgOg0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTUyLCAxOTcyLCAyMDAyLCAyMDA3KSwNCiAgICAgICAgIGNvdW50cnkgPT0gIk1leGljbyIpDQpgYGANCg0KDQpBaG9yYSwgc2kgZGVzZcOhcmFtb3Mgb2J0ZW5lciB1bmEgc3ViZ3LDoWZpY2EgZGUgbMOtbmVhcyBkZSBjdWF0cm8gcGHDrXNlcyBhc2nDoXRpY29zIChOZXBhbCwgSXJhaywgQ2FtYm9kaWEgeSBDaGluYSksIGxvIHBvZHLDrWFtb3MgaGFjZXIgZGUgbGEgc2lndWllbnRlIGZvcm1hOg0KDQokeSA9IDN4ICsgNCQNCg0KeSB+IDN4ICsgNA0KDQpgYGB7ciBnYXAgcGxvdCBmYWNldHMgY291bnRyeX0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiTmVwYWwiLCAiSXJhcSIsICJDYW1ib2RpYSIsIkNoaW5hIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHApKSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfd3JhcCh2YXJzKGNvdW50cnkpKSArICMgcG9kcsOtYSBzZXIgdG1iIGZhY2V0X3dyYXAofiBjb3VudHJ5KQ0KICBnZ3RpdGxlKCJTZXBhcmFjacOzbiBkZSBsb3MgcGHDrXNlcyBwb3IgZmFjZXRhcyIpDQpgYGANCg0KT3RyYSBhbHRlcm5hdGl2YSBzZXLDrWEgbW9zdHJhciB1bmEgc29sYSBncsOhZmljYSB5IGRlZmluaXIgZWwgY29sb3IgZGUgbMOtbmVhIHBvciBwYcOtcy4gQXF1w60gc2UgZWplbXBsaWZpY2EgdGFtYmnDqW4gY8OzbW8gY2FtYmlhciBlbCBub21icmUgZGUgbG9zIGVqZXMsIGxhIHBvc2ljacOzbiBkZSBsYSBsZXllbmRhLCBlbnRyZSBvdHJvcy4NCg0KYGBge3IgZ2FwIHBsb3QgY291bnRyeSBjb2xvcn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kb25lc2lhIiwiSW5kaWEiLCJPbWFuIiwgIlRhaXdhbiIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvdW50cnkpKSArDQogIGdlb21fbGluZSgpICsNCiAgeWxhYigiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIpICsgeGxhYigiIikgKw0KICBnZ3RpdGxlKCJDYW1iaW8gZGUgbGEgZXNwZXJhbnphIGRlIHZpZGEgcGFyYSBhbGd1bm9zIHBhaXNlcyBhc2nDoXRpY29zIikgKw0KICBsYWJzKGNvbG9yID0gIiIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KYGBgDQpPdHJhIG1hbmVyYSBkZSBlc3BlY2lmaWNhciBsb3Mgbm9tYnJlcyBkZSBlamVzIHkgZWwgdMOtdHVsbyBlcyBkaXJlY3RhbWVudGUgZGVudHJvIGRlIGBsYWJzKClgOg0KDQpgYGB7cn0NCml6cSA8LSB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibGVmdCIpDQoNCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiSW5kb25lc2lhIiwiSW5kaWEiLCJPbWFuIiwgIlRhaXdhbiIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBsaWZlRXhwLCBjb2xvciA9IGNvdW50cnkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh4ID0gIiIsIA0KICAgICAgIHkgPSAiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIsIA0KICAgICAgIHRpdGxlID0gIkNhbWJpbyBkZSBsYSBlc3BlcmFuemEgZGUgdmlkYSBlbiBhbGd1bm9zIHBhw61zZXMgYXNpw6F0aWNvcyIsIA0KICAgICAgIGNvbG9yID0gIiIpICsgDQogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTgsIA0KICAgICAgICAgICAgICAgIGJhc2VfZmFtaWx5ID0gInNlcmlmIiwNCiAgICAgICAgICAgICAgICBiYXNlX2xpbmVfc2l6ZSA9IDEpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpgYGANCg0KU2UgcG9kcsOtYW4gaGFjZXIgbcOhcyBjb25maWd1cmFjaW9uZXM6DQoNCmBgYHtyIGdhcCBwbG90IGNvdW50cnkgY29sb3IgbGluZXR5cGV9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkluZG9uZXNpYSIsIkluZGlhIiwiT21hbiIsICJUYWl3YW4iKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IGNvdW50cnkpKSArDQogIGdlb21fbGluZSgpICsNCiAgeWxhYigiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIpICsgDQogIHhsYWIoIiIpICsNCiAgZ2d0aXRsZSgiQ2FtYmlvIGRlIGxhIGVzcGVyYW56YSBkZSB2aWRhIHBhcmEgYWxndW5vcyBwYWlzZXMgYXNpw6F0aWNvcyIpICsNCiAgbGFicyhjb2xvciA9ICIiLCBsaW5ldHlwZSA9IiIpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQoNClBvZGVtb3MgYW5hbGl6YXIgbGEgcmVsYWNpw7NuIGVudHJlIGxhIGVzcGVyYW56YSBkZSB2aWRhIHkgZWwgUElCIHBlciBjw6FwaXRhLCB5YSBxdWUgc2UgZGljZSBxdWUgZXhpc3RlIHVuYSByZWxhY2nDs24gZGlyZWN0YSBlbnRyZSBhbWJhcy4NCg0KSGFyZW1vcyBlbCBhbsOhbGlzaXMgcGFyYSBlbCBhw7FvIDIwMDc6DQoNCg0KYGBge3IgZ2FwIGxpZmVFeHAgR0RQIDIwMDd9DQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb250aW5lbnQsDQogICAgICAgICAgICAgc2l6ZSA9IHBvcCkpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIHNjYWxlX3hfbG9nMTAoKSArDQogIHlsYWIoIkVzcGVyYW56YSBkZSB2aWRhIChhw7FvcykiKSArDQogIHhsYWIoIlBJQiBwZXIgY8OhcGl0YSAoVVNEIGNvbiBhanVzdGUgaW5mbGFjaW9uYXJpbywgZXNjYWxhIGxvZzEwKSIpICsgDQogIGxhYnMoY29sb3IgPSIiLCBzaXplPSIiKQ0KYGBgDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb3VudHJ5ICVpbiUgYygiQ2FuYWRhIiwgIk1leGljbyIsICJCcmF6aWwiKSwNCiAgICAgICAgIHllYXIgPT0gMjAwNykgJT4lIA0KICBzZWxlY3QoeWVhciwgY291bnRyeSwgcG9wKQ0KYGBgDQpTaSBxdWlzacOpcmFtb3MgZ3JhZmljYXIgbGEgcG9ibGFjacOzbiB0b3RhbCBwb3IgY29udGluZW50ZSwgZXN0byBlc3RhcsOtYSBtYWw6DQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHBvcCwgY29sb3IgPSBjb250aW5lbnQpKSArDQogIGdlb21fbGluZSgpDQpgYGANCg0KQ2FtYmlhcmxhIGEgdW5hIGdyw6FmaWNhIGRlIHB1bnRvcyAoZGlzcGVyc2nDs24pIG5vcyBlbXBpZXphIGEgZGFyIG3DoXMgY2xhcmlkYWQgZGUgcG9yIHF1w6kgZXN0YWJhIG1hbDogdGVuZW1vcyB1biBwdW50byBwb3IgY2FkYSBwYcOtcy4NCg0KYGBge3J9DQpnYXBtaW5kZXIgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9wLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9wb2ludCgpDQpgYGANClBvZHLDrWFtb3MgdmVybm9zIHRlbnRhZG9zIGEgcXVlcmVyIGZpbHRyYXIgbGEgdGFibGEgcG9yIGNvbnRpbmVudGUgeSBhw7FvLCBwYXJhIGx1ZWdvIGp1bnRhciB0b2RvIHkgZ3JhZmljYXJsby4gQWxnbyBjb21vOg0KDQpgYGB7cn0NCmFmNTIgPC0gZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQWZyaWNhIiwNCiAgICAgICAgIHllYXIgPT0gMTk1MikgJT4lIA0KICBzdW1tYXJpc2UocG9ibGFjaW9uX3RvdGFsID0gc3VtKHBvcCkpDQphZjU3IDwtIGdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb250aW5lbnQgPT0gIkFmcmljYSIsDQogICAgICAgICB5ZWFyID09IDE5NTcpICU+JSANCiAgc3VtbWFyaXNlKHBvYmxhY2lvbl90b3RhbCA9IHN1bShwb3ApKQ0KYGBgDQoNClBlcm8sIHLDoXBpZG8gbm9zIGRhbW9zIGN1ZW50YSBxdWUgZXN0byBzZXLDrWEgYmFzdGFudGUgbGFyZ28geSB0ZWRpb3NvLg0KDQoNCsK/Q8OzbW8gcG9kcsOtYW1vcyBncmFmaWNhciBsYSAqKnBvYmxhY2nDs24gdG90YWwqKiBwb3IgY29udGluZW50ZSwgYSBsbyBsYXJnbyBkZWwgdGllbXBvPyBUZW5kcsOtYW1vcyBxdWUgYWdyZWdhciBsYSBwb2JsYWNpw7NuIGRlIGNhZGEgcGHDrXMgZGUgY2FkYSBjb250aW5lbnRlIHkgZ3JhZmljYXIgZXNvLg0KDQpgYGB7cn0NCnRhYmxhIDwtIGdhcG1pbmRlciAlPiUgDQogIGdyb3VwX2J5KGNvbnRpbmVudCwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UocG9ibGFjaW9uID0gc3VtKHBvcCksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikNCnRhYmxhDQp0YWJsYSAlPiUgDQogIHN1bW1hcmlzZShwb2JfcHJvbWVkaW8gPSBtZWFuKHBvYmxhY2lvbikpDQoNCnRhYmxhICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9ibGFjaW9uLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9saW5lKCkNCmBgYA0KDQrCv0PDs21vIHBvZHLDrWFtb3MgYWdyZWdhciBsYSBwb2JsYWNpw7NuIHRvdGFsIGRlbCBtdW5kbyBhIGVzdGEgZ3LDoWZpY2E/ICgqTm90YTogbGEgZXNjYWxhIG5vIG5vcyBwZXJtaXRpcsOhIHZlciBiaWVuIGEgY2FkYSBjb250aW5lbnRlKikuDQoNCmBgYHtyfQ0KI3BvYmxhY2lvbiBtdW5kaWFsIHRvdGFsDQpwb2JfdG90YWwgPC0gZ2FwbWluZGVyICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpc2UocG9ibGFjaW9uID0gc3VtKHBvcCksIC5ncm91cHMgPSAiZHJvcF9sYXN0IikNCg0KZ19wb2IgPC0gZ2FwbWluZGVyICU+JSANCiAgZ3JvdXBfYnkoY29udGluZW50LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZShwb2JsYWNpb24gPSBzdW0ocG9wKSwgLmdyb3VwcyA9ICJkcm9wX2xhc3QiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcG9ibGFjaW9uLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgIyBwYXJhIGluY2x1aXIgbGEgcG9iLiBtdW5kaWFsIHRvdGFsOg0KICBnZW9tX2xpbmUoZGF0YSA9IHBvYl90b3RhbCwgYWVzKHggPSB5ZWFyLCB5ID0gcG9ibGFjaW9uKSwNCiAgICAgICAgICAgIGNvbG9yID0gImZpcmVicmljayIsIGxpbmV0eXBlID0gImRhc2hlZCIpDQpnX3BvYg0KIyBsYSBtaXNtYSBncsOhZmljYSwgZW4gZXNjYWxhIGxvZ2Fyw610bWljYQ0KZ19wb2IgKyBzY2FsZV95X2xvZzEwKCkNCmBgYA0KDQoNCg0KDQpQZXJvLCDCv3F1w6kgcGFzYSBzaSBxdWVyZW1vcyBvYnNlcnZhciBlbCBjYW1iaW8gZGUgZXN0b3MgZmFjdG9yZXMgYSBsbyBsYXJnbyBkZWwgdGllbXBvPyBDbGFybywgcG9kcsOtYW1vcyBjcmVhciBtdWNoYXMgZ3LDoWZpY2FzIGRpc3RpbnRhcywgY2FtYmlhbmRvIGVsIGFyZ3VtZW50byBgZmlsdGVyKHllYXIgPT0gImNhZGEgdW5vIGRlIGxvcyBhw7FvcyIpYC4gUGVybyBlc3RvLCBhcGFydGUgZGUgcXVlIHNlcsOtYSBsYWJvcmlvc28sIG5vIHNlcsOtYSBwcsOhY3RpY28gcGFyYSBhbmFsaXphcmxvLg0KDQojIEdyw6FmaWNhcyBpbnRlcmFjdGl2YXMgey50YWJzZXR9DQoNCiMjIGBwbG90bHlgDQoNCkxvIHF1ZSBwb2RlbW9zIGhhY2VyIGVzIGNyZWFyIHVuYSBncsOhZmljYSBpbnRlcmFjdGl2YSwgYXBveWFkb3MgZGUgbGEgcGFxdWV0ZXLDrWEgW2BwbG90bHlgXShodHRwczovL3Bsb3RseS5jb20vci8pLiBMb3MgY2FtYmlvcyBxdWUgdGVuZW1vcyBxdWUgaGFjZXIgZW4gZXN0ZSBjYXNvIGVuIHBhcnRpY3VsYXIgc29uIG11eSBzZW5jaWxsb3MuIFB1ZWRlbiBjb25zdWx0YXIgW2VzdGUgbGlicm8gZWxlY3Ryw7NuaWNvXShodHRwczovL3Bsb3RseS1yLmNvbS9pbmRleC5odG1sKSBwYXJhIG3DoXMgZGV0YWxsZXMuDQoNCiogSGFiZXIgaW5zdGFsYWRvIHkgY2FyZ2FkbyBgcGxvdGx5YA0KKiBBZ3JlZ2FyIGBhZXMoZnJhbWUgPSB5ZWFyKWAgYSBsYSBlc3TDqXRpY2EgZGUgbGEgZ3LDoWZpY2EuDQoqIEd1YXJkYXIgZWwgZ3LDoWZpY28gZW4gdW5hIHZhcmlhYmxlIChlbCBub21icmUgZXMgaW5kaWZlcmVudGUpLCB5IHBvc3Rlcmlvcm1lbnRlIGVqZWN1dGFyIGxhIGZ1bmNpw7NuIGBnZ3Bsb3RseSgpYCBjb24gbGEgdmFyaWFibGUgcXVlIGNvbnRpZW5lIGFsIGdyw6FmaWNvLg0KDQoqKk5PVEE6KiogQ2FzaSBjdWFscXVpZXIgZ3LDoWZpY28gaGVjaG8gY29uIGBnZ3Bsb3QyYCBzZSBwdWVkZSBjb252ZXJ0aXIgZW4gdW5vIGludGVyYWN0aXZvIGNvbiBsYSBmdW5jacOzbiBgZ2dwbG90bHkoKWAuDQoNCkNvbnZpcnRhbW9zIGxhIGdyw6FmaWNhIGFudGVyaW9yIGEgaW50ZXJhY3RpdmEsIHNpbXBsZW1lbnRlIGNvcnJpZW5kbyBsYSBmdW5jacOzbiBgZ2dwbG90bHkoKWANCg0KYGBge3J9DQpnZ3Bsb3RseShnX3BvYikNCmBgYA0KDQpgYGB7cn0NCmdhcG1pbmRlciAlPiUgDQogIGZpbHRlcihjb250aW5lbnQgPT0gIk9jZWFuaWEiLA0KICAgICAgICAgeWVhciA9PSAyMDA3KQ0KYGBgDQoNCg0KDQpgYGB7ciBwbG90bHkgZ2FwLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02fQ0KaW50X3Bsb3QxIDwtIGdhcG1pbmRlciAlPiUgDQogIGdncGxvdChhZXMoeCA9IGdkcFBlcmNhcCwgeSA9IGxpZmVFeHAsIGNvbG9yID0gY29udGluZW50LA0KICAgICAgICAgICAgIHNpemUgPSBwb3AsIGxhYmVsID0gY291bnRyeSkpICsNCiAgZ2VvbV9wb2ludChhZXMoZnJhbWUgPSB5ZWFyKSkgKyANCiAgc2NhbGVfeF9sb2cxMCgpICsgDQogIHlsYWIoIkVzcGVyYW56YSBkZSB2aWRhIChhw7FvcykiKSArDQogIHhsYWIoIlBJQiBwZXIgY8OhcGl0YSAoVVNEIGNvbiBhanVzdGUgaW5mbGFjaW9uYXJpbykiKSArIA0KICBsYWJzKGNvbG9yID0iIiwgc2l6ZT0iIikNCg0KZ2dwbG90bHkoaW50X3Bsb3QxKQ0KYGBgDQoNCmBgYHtyfQ0KcHJ1ZWJhIDwtIGdhcG1pbmRlciAlPiUgDQogIGZpbHRlcih5ZWFyID09IDIwMDcpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb3VudHJ5LA0KICAgICAgICAgICAgIHNpemUgPSBwb3AsIGxhYmVsID0gY291bnRyeSkpICsNCiAgZ2VvbV9wb2ludChhZXMoZnJhbWUgPSBjb250aW5lbnQpKSArIA0KICBzY2FsZV94X2xvZzEwKCkgKyANCiAgeWxhYigiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIpICsNCiAgeGxhYigiUElCIHBlciBjw6FwaXRhIChVU0QgY29uIGFqdXN0ZSBpbmZsYWNpb25hcmlvKSIpICsgDQogIGxhYnMoY29sb3IgPSIiLCBzaXplPSIiKQ0KDQpnZ3Bsb3RseShwcnVlYmEpDQpgYGANCg0KDQoNCmBgYHtyIHBsb3RseSBieSBmYWNldHMsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9DQppbnRfcGxvdDIgPC0gZ2FwbWluZGVyICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sb3IgPSBjb3VudHJ5LA0KICAgICAgICAgICAgIHNpemUgPSBwb3AsIGxhYmVsID0gY291bnRyeSkpICsNCiAgZ2VvbV9wb2ludChhZXMoZnJhbWUgPSB5ZWFyKSkgKyANCiAgc2NhbGVfeF9sb2cxMCgpICsgDQogIGZhY2V0X3dyYXAofiBjb250aW5lbnQpICsNCiAgeWxhYigiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIpICsNCiAgeGxhYigiUElCIHBlciBjw6FwaXRhIChVU0QgY29uIGFqdXN0ZSBpbmZsYWNpb25hcmlvKSIpICsgDQogICMgbGFicyhjb2xvciA9IiIsIHNpemU9IiIpDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KICANCmdncGxvdGx5KGludF9wbG90MikNCmBgYA0KDQpPdHJvIHRpcG8gZGUgZ3LDoWZpY28gcXVlIHB1ZWRlIHByb3BvcmNpb25hcm5vcyBtdWNoYSBpbmZvcm1hY2nDs24gZXMgdW4gKmRpYWdyYW1hIGRlIGNhamEgeSBiaWdvdGVzKi4gQXF1w60sIGxhIGludGVycHJldGFjacOzbiBlcyBhbGdvIGFzw606DQoNCiogTG9zIGJpZ290ZXMgbXVlc3RyYW4gbG9zIHZhbG9yZXMgbcOtbmltbyB5IG3DoXhpbW8gKHNpbiBjb25zaWRlcmFyICpvdXRsaWVycyopLA0KKiBlbCBpbmljaW8gZGUgbGEgY2FqYSByZXByZXNlbnRhIGVsIHByaW1lciBjdWFydGlsICgyNSUgZGUgbG9zIGRhdG9zKSwNCiogTGEgbMOtbmVhIGludGVybmEgZGUgbGEgY2FqYSBlcyBsYSBtZWRpYW5hIChlbCA1MCUgZGUgbG9zIGRhdG9zKSwNCiogZWwgZmluYWwgZGUgbGEgY2FqYSBtdWVzdHJhIGVsIHRlcmNlciBjdWFydGlsICg3NSUgZGUgbG9zIGRhdG9zKSB5LA0KKiBlbiBjYXNvIGRlIHF1ZSBsYSBncsOhZmljYSBtdWVzdHJlIHB1bnRvcyBmdWVyYSBkZSBsYSBjYWphLCBzZSBjb25zaWRlcmFyw61hbiBjb21vICpvdXRsaWVycyouDQoNCmBgYHtyfQ0KZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMjAwNykgJT4lIA0KICBzdW1tYXJpc2UoZXNwZXJhbnphX3ZpZGEgPSBtZWFuKGxpZmVFeHApKQ0KDQpnYXBtaW5kZXIgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDA3KSAlPiUgDQogIGdyb3VwX2J5KGNvbnRpbmVudCkgJT4lIA0KICBzdW1tYXJpc2UoZXNwZXJhbnphX3ZpZGEgPSBtZWFuKGxpZmVFeHApKQ0KYGBgDQoNCg0KYGBge3IgZ2FwIGJveHBsb3R9DQpnYXBfYm94IDwtIGdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKHllYXIgPT0gMjAwNykgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBjb250aW5lbnQsIHkgPSBsaWZlRXhwKSkgKw0KICBnZW9tX2JveHBsb3QoKQ0KDQpnZ3Bsb3RseShnYXBfYm94KQ0KYGBgDQoNCkRlZmluaWVuZG8gdW5hIGZ1bmNpw7NuIGVzcGVjaWFsLCBzZSBwdWVkZW4gY3JlYXIgZ3LDoWZpY2FzIGFjdW11bGF0aXZhcyBkZSBsw61uZWFzIHRhbWJpw6luOg0KDQpgYGB7ciBwbG90bHkgY3VtdWxhdGl2ZSBsaW5lfQ0KaW52aXNpYmxlKGdldFN5bWJvbHMoIkFBUEwiLHNyYz0neWFob28nKSkNCg0KZGYgPC0gZGF0YS5mcmFtZShEYXRlPXpvbzo6aW5kZXgoQUFQTCksY29yZWRhdGEoQUFQTCkpDQpkZiA8LSB0YWlsKGRmLCAzMCkNCmRmJElEIDwtIHNlcS5pbnQobnJvdyhkZikpDQoNCmFjY3VtdWxhdGVfYnkgPC0gZnVuY3Rpb24oZGF0LCB2YXIpIHsNCiAgdmFyIDwtIGxhenlldmFsOjpmX2V2YWwodmFyLCBkYXQpDQogIGx2bHMgPC0gcGxvdGx5Ojo6Z2V0TGV2ZWxzKHZhcikNCiAgZGF0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKGx2bHMpLCBmdW5jdGlvbih4KSB7DQogICAgY2JpbmQoZGF0W3ZhciAlaW4lIGx2bHNbc2VxKDEsIHgpXSwgXSwgZnJhbWUgPSBsdmxzW1t4XV0pDQogIH0pDQogIGRwbHlyOjpiaW5kX3Jvd3MoZGF0cykNCn0NCg0KZGYgPC0gZGYgJT4lDQogIGFjY3VtdWxhdGVfYnkofklEKQ0KDQpwIDwtIGdncGxvdChkZixhZXMoSUQsIEFBUEwuQ2xvc2UsIGZyYW1lID0gZnJhbWUpKSArDQogIGdlb21fbGluZSgpDQoNCmZpZyA8LSBnZ3Bsb3RseShwKSAlPiUNCiAgbGF5b3V0KA0KICAgIHRpdGxlID0gIkFBUEw6IExhc3QgMzAgZGF5cyIsDQogICAgeWF4aXMgPSBsaXN0KA0KICAgICAgdGl0bGUgPSAiQ2xvc2UiLA0KICAgICAgemVyb2xpbmUgPSBGLA0KICAgICAgdGlja3ByZWZpeCA9ICIkIg0KICAgICksDQogICAgeGF4aXMgPSBsaXN0KA0KICAgICAgdGl0bGUgPSAiRGF5IiwNCiAgICAgIHplcm9saW5lID0gRiwgDQogICAgICBzaG93Z3JpZCA9IEYNCiAgICApDQogICkgJT4lIA0KICBhbmltYXRpb25fb3B0cygNCiAgICBmcmFtZSA9IDEwMCwgDQogICAgdHJhbnNpdGlvbiA9IDAsIA0KICAgIHJlZHJhdyA9IEZBTFNFDQogICkgJT4lDQogIGFuaW1hdGlvbl9zbGlkZXIoDQogICAgY3VycmVudHZhbHVlID0gbGlzdCgNCiAgICAgIHByZWZpeCA9ICJEYXkgIg0KICAgICkNCiAgKQ0KDQpmaWcNCmBgYA0KDQoNCmBgYHtyfQ0KR3LDoWZpY28yIDwtIGdhcG1pbmRlciAlPiUNCiAgZ3JvdXBfYnkoY29udGluZW50LCB5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKHBvYmxhY2lvbiA9IHN1bShwb3ApLCAuZ3JvdXBzID0gImRyb3BfbGFzdCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gcG9ibGFjaW9uLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9wb2ludChhZXMoZnJhbWUgPSB5ZWFyKSkgKyANCiAgeWxhYigiUG9ibGFjacOzbiIpICsNCiAgeGxhYigiQcOxbyIpICsgDQogIGxhYnMoY29sb3IgPSIiLCBzaXplPSIiKQ0KDQogDQoNCmdncGxvdGx5KEdyw6FmaWNvMikNCmBgYA0KDQoNCg0KIyMgYGdnYW5pbWF0ZWANCg0KRXN0byBubyBmdW5jaW9uYSBpZ3VhbCBwYXJhIHVuIGdyw6FmaWNvIGRlIGzDrW5lYXMuIEV4aXN0ZSBvdHJhIHBhcXVldGVyw61hIHF1ZSBub3MgcGVybWl0ZSBoYWNlciBjb3NhcyBzaW1pbGFyZXM6IFtgZ2dhbmltYXRlYF0oaHR0cHM6Ly9nZ2FuaW1hdGUuY29tL2FydGljbGVzL2dnYW5pbWF0ZS5odG1sKS4gW0VzdGEgcMOhZ2luYV0oaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL2dnYW5pbWF0ZS1ob3ctdG8tY3JlYXRlLXBsb3RzLXdpdGgtYmVhdXRpZnVsLWFuaW1hdGlvbi1pbi1yLykgY29udGllbmUgdW4gYnJldmUgdHV0b3JpYWwgZGUgdmFyaWFzIG9wY2lvbmVzLg0KDQoqKk5PVEE6KiogKlNlIHJlcXVpZXJlIGluc3RhbGFyIGxhcyBwYXF1ZXRlcsOtYXMgYHBuZ2AgeSBgZ2lmc2tpYCBhZGljaW9uYWxlcyBhIGBnZ2FuaW1hdGVgLg0KDQpgYGB7ciBnZ2FuaW1hdGUsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBldmFsPUZBTFNFfQ0KcDEgPC0gZ2FwbWluZGVyICU+JSANCiAgZmlsdGVyKGNvdW50cnkgJWluJSBjKCJNZXhpY28iLCAiVW5pdGVkIFN0YXRlcyIsICJDaGlsZSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpZmVFeHAsDQogICAgICAgICAgICAgY29sb3IgPSBjb3VudHJ5KSkgKyANCiAgZ2VvbV9saW5lKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBsYWJzKHggPSAiQcOxbyIsIHkgPSAiRXNwZXJhbnphIGRlIHZpZGEgKGHDsW9zKSIsIA0KICAgICAgIHRpdGxlID0gIkV2b2x1Y2nDs24gZGUgbGEgZXNwZXJhbnphIGRlIHZpZGEgZW4gZWwgdGllbXBvIikNCg0KcDEgKyB0cmFuc2l0aW9uX3JldmVhbCh5ZWFyKQ0KDQphbmltX3NhdmUoZmlsZW5hbWUgPSAiZmlncy9MaWZlRXhwX2dnYW5pbS5naWYiKQ0KYGBgDQoNCiFbXShmaWdzL0xpZmVFeHBfZ2dhbmltLmdpZikNCg0KDQoNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZScsIGV2YWw9RkFMU0V9DQpwIDwtIGdncGxvdCgNCiAgYWlycXVhbGl0eSwNCiAgYWVzKERheSwgVGVtcCwgZ3JvdXAgPSBNb250aCwgY29sb3IgPSBmYWN0b3IoTW9udGgpKQ0KICApICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArDQogIGxhYnMoeCA9ICJEYXkgb2YgTW9udGgiLCB5ID0gIlRlbXBlcmF0dXJlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCg0KcCArIHRyYW5zaXRpb25fcmV2ZWFsKERheSkNCg0KYW5pbV9zYXZlKGZpbGVuYW1lID0gImZpZ3MvYWlycXVhbGl0eS5naWYiKQ0KYGBgDQohW1RlbXBlcmF0dXJhIHBvciBkw61hLCBwb3IgbWVzXShmaWdzL2FpcnF1YWxpdHkuZ2lmKQ0KDQoNCg0KDQo=